Pytanie w sprawie polymorphism, virtual, c++ – Wielkość klas w przypadku dziedziczenia wirtualnego

3

Czy ktoś może wyjaśnić wielkość klas w przypadku dziedziczenia wirtualnego z użyciem funkcji wirtualnych.

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

Wynik wielkości klas jest następujący:

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

Kompilatorem, którego używam, jestgcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)

@DumbCoder: Nie takie proste. ZAvptr jest potrzebny do wirtualnej tabeli, ale potrzebujesz dodatkowych wskaźników dla wirtualnych baz. David Rodríguez - dribeas
Dodaj rozmiar vptr do swojego rozmiaru klasy. Więcej informacji ->stackoverflow.com/questions/1604176/size-of-virtual-pointer-c DumbCoder
@FredLarson ... wiem o wielkości w przypadku klas polimorficznych, na które wpływa wirtualny wskaźnik ... ale jaki jest efekt dziedziczenia wirtualnie? Czy istnieje jakiś ukryty wskaźnik, gdy dziedziczymy wirtualnie? Kundan Kumar
@DumbCOder: Może być więcej niż jeden vptr. SigTerm

Twoja odpowiedź

4   odpowiedź
-1

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

Gdzie:

vptrs zajmują po 4 bajty każdy (wskaźniki 64-bitowe)tablice char mają po 4 bajty (zaokrąglane w górę w celu wyrównania)k ', j' i i 'są kopiami tych zmiennych, które są dziedziczone przez C, a nie B.
Ach, racja, dobry punkt. Edward Loper
C nie rozszerza B, więc nie zawiera j. Dodatkowe 4 to wskaźnik do podobiektu A David Rodríguez - dribeas
1

sizeof(C) wiecej niżsizeof(B) ponieważ obiekt typu C (ponieważ dziedziczy wirtualnie z A) będzie zawierał wskaźnik (oprócz vptr, który również będzie zawierał obiekty typu B) wskazujący na jego część odziedziczoną po A. Scott Meyers wyjaśnia to w szczegół (około 10 stron) w pozycji 24: „Zrozumienie kosztów funkcji wirtualnych, wielokrotnego dziedziczenia, wirtualnych klas bazowych i RTTI” jego książkiBardziej efektywny C ++

6

3 bajty w tablicy, 1 bajtowe wypełnienie, 4 bajty dla vptr (wskaźnik do vtable)

sizeof (B): 12

Podobiekt: 8, 3 bajty dla dodatkowej tablicy, 1-bajtowe wypełnienie

sizeof (C): 16

Jest to prawdopodobnie zaskakujące dla ciebie ... Podobiekt: 8, 3 bajty dla dodatkowej tablicy, 1 bajtowe wypełnienie,4 bajty wskaźnika do A

Za każdym razem, gdy masz wirtualne dziedziczenie, położenie wirtualnego podobiektu bazowego względem początku kompletnego typu jest nieznane, więc do oryginalnego obiektu dodawany jest dodatkowy wskaźnik, aby śledzić, gdzie znajduje się baza wirtualna. Rozważmy następujący przykład:

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

LokalizacjaA w odniesieniu do początkuB obiekt, gdy kompletny typ to aB może być inny niż lokalizacjaA obiekt podrzędnyB kiedy jest częścią końcowego obiektuD. Jeśli nie jest to oczywiste, załóżmy, że względna lokalizacja jest taka sama i sprawdź, czy względna lokalizacjaA z szacunkiem doC wC ostateczny obiekt lubC obiekt podrzędnyD można również utrzymać.

Jeśli chodzi o ostatni przykład, nie mam ochoty go analizować ... ale możesz przeczytaćItanium C ++ ABI do konkretnej implementacji modelu obiektowego C ++. Wszystkie inne implementacje nie różnią się zbytnio.

Ostatni przykład:

sizeof (D): 32

D zawiera podobiekt B (12) i podobiekt C (16) oraz dodatkową tablicę o rozmiarze 3 i jeden dodatkowy bit wypełnienia 1.

W tym konkretnym przypadku pojawia się pytanie, dlaczego są dwaA podobiekty, jeśliC dziedziczy wirtualnie zAodpowiedź brzmi, że wirtualna baza oznacza, że ​​obiekt chce dzielić tę bazę z jakimkolwiek innym typem w hierarchii, który również chce się nią podzielić. Ale w tym przypadkuB nie chce się nim dzielićA podobiekt, takC potrzebuje własnego.

Powinieneś być w stanie to śledzić, dodając dzienniki do konstruktorów na różnych poziomach. W przypadkuA niech pobierze wartość w kompilatorze i przekaże różne wartości z każdej klasy rozszerzającej.

0

można powiedzieć, że kompilator nie wyrówna go w pamięci za pomocą pakietu #pragma (1). Aby zapisać bieżące ustawienia pakowania i przywrócić je później, możesz również użyć pakietu #pragma pack (push) i #pragma (pop).

Powiązane pytania