2012-10-31 11 views
9

W poniższym kodzie są z książki "Inside C++ modelu obiektowego"pytania o C++ dziedziczenia wirtualnego

#include <iostream> 
using namespace std; 
class X{}; 
class Y: public virtual X{}; 
class Z: public virtual X{}; 
class A: public Y, public Z{}; 

int main() 
{ 
    cout<<sizeof(X)<<" "<<sizeof(Y)<<" "<<sizeof(Z)<<" "<<sizeof(A)<<endl; 
    return 0; 
} 

w moim komputerze (Windows VS2010), wyjście jest:

Here're moje pytania

1, sizeof (x) = 1

książka powiedzieć s gdy typ X generuje dwie instancje, na przykład xa i xb. kompilacja wstawi bajt do A, aby xa i xb mogły mieć inny adres. Nie do końca rozumiem powody.

2 sizeof (T) = 4

Stosując wirtualny spadku, będziemy mieli dodatkowy wirtualny wskaźnik? Wydaje mi się, że może to być odmienne od wirtualnego wskaźnika w polimorfizmie. Czy ktoś może mi podać układ pamięci dla Y?

Dziękujemy!

+0

Jedno pytanie na pytanie proszę –

+0

na pierwsze pytanie, sprawdź: http://stackoverflow.com/questions/621616/c-what-is-the-size-of-an- object-of-an-empty-class? rq = 1 –

+1

Myślę, że twoje główne pytanie jest takie, że ponieważ Y używa wirtualnego dziedziczenia do wyprowadzenia z nie-polimorficznej klasy X, a Y samo w sobie nie jest polimorficzne, to samo dziedziczenie samo spowoduje Y mieć v-table, więc jego rozmiar to 4 .. – CashCow

Odpowiedz

6
  1. kompilator nowy znak, gdy klasa jest pusty, więc może generować inny obiekt
  2. sizeof (T) = 4, ponieważ znajduje się w wirtualnym dziedziczenie, konstrukcja wygeneruje tabelę vptr, która jest 4 bajty w 32-bitowym systemie
  3. jeśli używasz visual studio use/d1reportAllClassLayout we właściwościach-> C/C++/Command do generowania układu obiektów klasa Y obiekt układ będzie na Visual Studio:
  4. książka 'Inside C++ model obiektowy' Stanley B. Lippman wyjaśnił to bardzo dobrze


     class Y size(4): 
      +--- 
      0  | {vbptr} 
      +--- 
      +--- (virtual base X) 
      +---
Y::[email protected]: 0 | 0 1 | 4 (Yd(Y+0)X)

vbi: class offset o.vbptr o.vbte fVtorDisp X 4 0 4 0
1

sizeof pustej klasy zawsze zwraca 1. To jest pojedynczy bajtowy bajt dla pustej klasy.

A posiada dwie pozycje w tabeli wirtualnych jeden dla Y inny dla Z

Więc sizeof dwa wskaźniki tj 8.

Y i Z posiadają obie mają pojedynczy wpis X w tabela wirtualnych, a tym samym rozmiar jest 4.

+0

Nie widzę tutaj klas B i C – CashCow

1

An obiekt będzie obejmować przedmiot Y, obiekt oo (w tej kolejności) i tylko jeden obiekt X (wskazywany przez wskaźniki w Y i Z), ponieważ zarówno Y, jak i Z dziedziczą wirtualnie z X, co oznacza, że ​​gdy pojawi się wiele dziedzin, tylko jeden obiekt X będzie instantiatet w klasach potomnych. Nieruchomość ma dwa obiekty (jeden Y, jeden Z), a zatem ma sizeof = 8 (ponieważ oba mają sizeof = 4). Ale oba wskaźniki w Y i Z w obiekcie X wskażą ten sam adres.

drzewo dziedziczenia będzie wyglądać następująco:

X 
/\ 
Y Z 
\/
    A 
0

Powodem zajęcia -must- wynosić co najmniej 1 bajt to, że mamy tablicę X.Jeśli byłyby to 0 bajtów, to tablica & [1] miałby ten sam adres co tablica &, której nikt by się nie spodziewał, złamałby kod, byłby irytujący gdybyś musiał napisać kod, by to sprawdzić i zazwyczaj nie robi jakiś sens.

Y byłoby po prostu

static void* virtual_ptr1 //note this is in virtual table and cannot be edited 

Można myśleć o vtables (wirtualne wskaźniki do klas i funkcji wirtualnych) jako zmiennych statycznych, że nie można edytować ręcznie/kodu (lub przynajmniej nie powinien). Pomyśl o tym, jak kompilator zarezerwował zmienne statyczne

+1

Podoba mi się to wyjaśnienie z powodu sizeof (X) = 1 – Junjie