Pregunta sobre polymorphism, c++, virtual – Tamaño de las clases en caso de herencia virtual.

3

Alguien puede explicar el tamaño de las clases en el caso de herencia virtual que involucra funciones virtuales.

<code>   class A{
          char k[ 3 ];
          public:
          virtual void a(){};
          };

   class B : public  A{
          char j[ 3 ];
          public:
          virtual  void b(){};
          };

   class C : public virtual A{
          char i[ 3 ];
          public:
          virtual void c(){};
          };

   class D : public B, public C{
          char h[ 3 ];
          public:
          virtual void d(){};
          };
</code>

La salida del tamaño de las clases es:

<code>    sizeof(A): 8
    sizeof(B): 12
    sizeof(C): 16
    sizeof(D): 32
</code>

El compilador que estoy usando esgcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)

@DumbCOder: Puede haber más de un vptr. SigTerm
Agregue el tamaño de un vptr en su tamaño de la clase. Para más detalles ->stackoverflow.com/questions/1604176/size-of-virtual-pointer-c DumbCoder
Tenga en cuenta que todos los subobjetos de base no vacíos deben estar alineados correctamente. Por lo tanto, puede considerar que cada clase tenga un solo miembro de 4 bytes alineado en 4 si así lo desea. Kerrek SB
@DumbCoder: No es tan simple. UNAvptr es necesario para la tabla virtual, pero necesita punteros adicionales para las bases virtuales. David Rodríguez - dribeas

Tu respuesta

4   la respuesta
0

puede decir que el compilador no lo alinee en la memoria usando #pragma pack (1). Para guardar las configuraciones de embalaje actuales y restaurarlas más tarde, también puede usar #pragma pack (push) y #pragma pack (pop).

6

3 bytes en la matriz, relleno de 1 byte, 4 bytes para el vptr (puntero a la vtable)

tamaño de (B): 12

Un subobjeto: 8, 3 bytes para la matriz adicional, relleno de 1 byte

tamaño de (C): 16

Este es probablemente el sorprendente para usted ... Un subobjeto: 8, 3 bytes para la matriz adicional, relleno de 1 byte,Puntero de 4 bytes a A

Siempre que tenga herencia virtual, la ubicación del subobjeto de base virtual con respecto al inicio del tipo completo es desconocida, por lo que se agrega un puntero adicional al objeto original para rastrear dónde se encuentra la base virtual. Considera este ejemplo:

<code>struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B, C {};
</code>

La ubicación deA con respecto al inicio de laB objeto cuando el tipo completo es unB puede ser diferente a la ubicación de laA subobjeto deB cuando es parte del objeto finalD. Si esto no es obvio, suponga que la ubicación relativa es la misma, y ​​verifique si la ubicación relativa deA con respecto aC en unC objeto final o unC subobjeto enD También se puede mantener.

En cuanto al último ejemplo, no tengo ganas de analizarlo ... pero puedes leer elItanium C ++ ABI Para una implementación concreta del modelo de objetos C ++. Todas las otras implementaciones no difieren mucho.

Último ejemplo:

tamaño de (D): 32

D contiene un subobjeto B (12) y un subobjeto C (16), más una matriz adicional de tamaño 3 y un bit adicional de relleno 1.

En este caso particular, la pregunta que podría surgir es por qué hay dosA subobjetos siC hereda virtualmente deA, y la respuesta es que la base virtual significa que el objeto está dispuesto a compartir esta base con cualquier otro tipo en la jerarquía que también está dispuesto a compartirla. Pero en este casoB no esta dispuesto a compartir esA subobjeto, entoncesC necesita es propio.

Debería poder realizar un seguimiento de esto agregando registros a los constructores en los diferentes niveles. En el caso deA haga que tome un valor en el compilador y pase valores diferentes de cada clase extendida.

-1

Esta es mi mejor estimación de dónde se están utilizando todos los bytes:

<code>              Avptr Bvptr CVptr DVptr k j i h k' j' i'  TOTAL
============= ========================================= =====
sizeof(A): 8    4                     4                   8
sizeof(B): 12        4                4 4                12
sizeof(C): 16              4          4 4 4              16
sizeof(D): 32                    4    4 4 4 4  4  4  4   32
</code>

Dónde:

los vptrs toman 4 bytes cada uno (punteros de 64 bits)los arrays de caracteres toman 4 bytes cada uno (redondeados para alineación)k ', j' e i 'son las copias de aquellas variables que se heredan a través de C, en lugar de B.
Ah, cierto, buen punto. Edward Loper
C no extiende B, por lo que no contiene j. Los 4 extra hay un puntero al subobjeto A David Rodríguez - dribeas
1

sizeof(C) Es mas quesizeof(B) porque un objeto de tipo C (porque se hereda virtualmente de A) contendrá un puntero (aparte de un vptr que también contendrán los objetos de tipo B) que apunta a la parte de sí mismo que heredó de A. Scott Meyers explica esto en detalle (alrededor de 10 páginas) en el Ítem 24: 'Comprender los costos de las funciones virtuales, herencia múltiple, clases de base virtual y RTTI' de su libroC ++ más eficaz

Preguntas relacionadas