Pergunta sobre virtual, polymorphism, c++ – Tamanho das classes no caso de herança virtual

3

Alguém pode explicar sobre o tamanho das classes no caso de herança virtual envolvendo funções virtuais.

<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>

A saída do tamanho das classes é:

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

O compilador que estou usando égcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)

O que te surpreende sobre esses tamanhos? Fred Larson
@DumbCOder: Podem ser mais de um vptr. SigTerm
@DumbCoder: Não é tão simples. UMAvptr é necessário para a tabela virtual, mas você precisa de ponteiros extras para as bases virtuais. David Rodríguez - dribeas
Tenha em mente que todos os subobjetos base não vazios precisam estar alinhados adequadamente. Assim, você pode considerar que cada classe tenha um único membro de 4 bytes alinhado em 4, se desejar. Kerrek SB

Sua resposta

4   a resposta
1

sizeof(C) é mais quesizeof(B) porque um objeto do tipo C (porque ele é herdado virtualmente de A) conterá um ponteiro (além de um vptr que objetos do tipo B também conterão) apontando para a parte de si mesmo que herdou de A. Scott Meyers explica isso em detalhe (cerca de 10 páginas) no Item 24: 'Entenda os custos de funções virtuais, herança múltipla, classes base virtuais e RTTI' de seu livroC ++ Mais Eficaz

0

você pode dizer ao compilador para não alinhá-lo na memória usando o #pragma pack (1). Para salvar as configurações atuais de empacotamento e restaurá-las mais tarde, você também pode usar #pragma pack (push) e #pragma pack (pop).

6

3 bytes na matriz, 1 byte padding, 4 bytes para o vptr (ponteiro para o vtable)

Tamanho de (B): 12

Um subobjeto: 8, 3 bytes para o array extra, preenchimento de 1 byte

Tamanho de (C): 16

Este é provavelmente o mais surpreendente para você ... Um subobjeto: 8, 3 bytes para o array extra, 1 byte padding,Ponteiro de 4 bytes para A

Sempre que você tiver herança virtual, a localização do subobjeto base virtual em relação ao início do tipo completo é desconhecida, portanto, um ponteiro extra é adicionado ao objeto original para rastrear onde está a base virtual. Considere este exemplo:

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

A localização deA em relação ao início doB objeto quando o tipo completo é umB pode ser diferente da localização doA subobjeto deB quando faz parte do objeto finalD. Se isso não for óbvio, assuma que a localização relativa é a mesma e verifique se a localização relativaA em relação aC em umC objeto final ou umC subobjeto emD também pode ser mantido.

Quanto ao último exemplo, não sinto vontade de analisá-lo ... mas você pode ler oItanium C ++ ABI para uma implementação concreta do modelo de objeto C ++. Todas as outras implementações não diferem muito.

Último exemplo:

Tamanho de (D): 32

D contém um sub-objeto B (12) e um sub-objeto C (16), além de uma matriz adicional de tamanho 3 e um bit extra de preenchimento 1.

Neste caso em particular, a questão que pode surgir é por que existem doisA subobjetos seC herda virtualmente deAe a resposta é que a base virtual significa que o objeto está disposto a compartilhar essa base com qualquer outro tipo na hierarquia que também esteja disposto a compartilhá-la. Mas neste casoB não está disposto a compartilhar éA subobjeto, entãoC precisa do seu próprio.

Você deve conseguir acompanhar isso adicionando logs aos construtores nos diferentes níveis. No caso deA ter um valor no compilador e passar valores diferentes de cada classe de extensão.

-1

os:

<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>

Onde:

os vptrs recebem 4 bytes cada (ponteiros de 64 bits)as matrizes de caracteres levam 4 bytes cada (arredondadas para alinhamento)k ', j' ei 'são as cópias dessas variáveis ​​que são herdadas via C, em vez de B.
C não estende B, portanto, não contém j. O extra 4, há um ponteiro para o subobjeto A David Rodríguez - dribeas
Ah, certo, bom ponto. Edward Loper

Perguntas relacionadas