2008-12-28 14 views
12

Die folgenden Code druckt 20, dh sizeof (z) 20.Frage zur Mehrfachvererbung, virtuellen Basisklassen und Objektgröße in C++

#include <iostream.h> 
class Base 
{ 
     public: 
      int a; 
}; 

class X:virtual public Base 
{ 
     public: 
      int x; 
}; 

class Y:virtual public Base 
{ 
     public: 
      int y; 
}; 

class Z:public X,public Y 
{ 
}; 

int main() 
{ 
Z z; 
cout << sizeof(z) <<endl; 
} 

Während, wenn ich verwende virtuelle Basisklassen nicht hier, dh für den folgenden Code: sizeof (z) ist 16.

#include <iostream.h> 
class Base 
{ 
     public: 
      int a; 
}; 

class X:public Base 
{ 
     public: 
      int x; 
}; 

class Y:public Base 
{ 
     public: 
      int y; 
}; 

class Z:public X,public Y 
{ 
}; 

int main() 
{ 
Z z; 
cout << sizeof(z) <<endl; 
} 

Warum ist sizeof (z) mehr (20) im ersten Fall? Sollte es nicht 12 sein, da Base nur einmal in Z enthalten ist?

Antwort

20

Blick Lassen Sie sich bei der Klasse Layout der beiden Fälle.

Ohne das virtuelle haben Sie zwei Basisklassen ("X" und "Y") mit jeweils einer ganzen Zahl, und jede dieser Klassen hat in ihnen eine Basisklasse "Base" integriert, die auch eine ganze Zahl hat. Das sind 4 ganze Zahlen, jeweils 32 Bits, die insgesamt 16 Bytes ergeben.

Offset Size Type Scope Name 
    0  4 int Base  a 
    4  4 int  X  x 
    8  4 int Base  a 
    12  4 int  Y  y 
    16 size (Z members would come at the end) 

(Edit:. Ich habe ein Programm in DJGPP geschrieben, um das Layout zu erhalten und gezwickt die Tabelle dafür zur Rechenschaft ziehen)

Nun lassen Sie uns über virtuelle Basisklassen sprechen: sie die tatsächliche Instanz ersetzen die Klasse mit einem Zeiger auf eine gemeinsame Instanz. Ihre "Z" -Klasse hat nur eine "Basis" -Klasse und beide Instanzen von "X" und "Y" zeigen darauf. Daher haben Sie Ganzzahlen in X, Y und Z, aber Sie haben nur die eine Z. Das heißt, Sie haben drei ganze Zahlen oder 12 Bytes. Aber X und Y haben auch einen Zeiger auf das geteilte Z (sonst wüssten sie nicht, wo sie es finden). Auf einer 32-Bit-Maschine fügen zwei Zeiger weitere 8 Byte hinzu. Dies ergibt die 20, die Sie sehen. Das Speicherlayout könnte wie folgt aussehen (ich habe es nicht überprüft ... die ARM ein Beispiel hat, wo die Reihenfolge X, Y, Z, dann Base):

Offset Size  Type Scope Name Value (sort of) 
    0  4 Base offset  X  ? 16 (or ptr to vtable) 
    4  4   int  X  x 
    8  4 Base offset  Y  ? 16 (or ptr to vtable) 
    12  4   int  Y  y 
    16  4   int Base  a 
    20 size (Z members would come before the Base) 

So ist der Speicher Differenz a Kombination zweier Dinge: eine weniger ganze Zahl und zwei weitere Zeiger. Im Gegensatz zu einer anderen Antwort glaube ich nicht, dass Vtables eine direkte (/ editierte) Rolle in diesem Bereich bezahlen, da es keine virtuellen Funktionen gibt.

Edit: ppinsider hat weitere Informationen zum gcc-Fall bereitgestellt, in dem er demonstriert, dass gcc den Zeiger auf die virtuelle Basisklasse implementiert, indem er eine ansonsten leere vtable verwendet (d. H. Keine virtuellen Funktionen). Auf diese Weise würde es, wenn es virtuelle Funktionen gäbe, keinen zusätzlichen Zeiger in der Klasseninstanz erfordern, der mehr Speicher benötigt. Ich vermute, der Nachteil ist eine zusätzliche Indirektion, um zur Basisklasse zu gelangen.

Wir könnten alle Compiler erwarten, dass dies zu tun, aber vielleicht auch nicht. Die ARM Seite 225 behandelt virtuelle Basisklassen ohne Erwähnung von VTables. Seite 235 adressiert insbesondere "virtuelle Basisklassen mit virtuellen Funktionen" und weist ein Diagramm auf, das ein Speicherlayout angibt, in dem Zeiger von den X- und Y-Teilen vorhanden sind, die von den Zeigern zu der V-Tabelle getrennt sind. Ich würde jedem empfehlen, nicht davon auszugehen, dass der Zeiger auf Base in Form einer Tabelle implementiert wird.

+0

Mark, wie hast du dieses Layout erstellt? –

+0

Wenn Sie das Tabellenformat meinen, ist es nur Code. Ich habe nur an den Inhalt gedacht. Ich bearbeite meine Antwort mit weiteren Details und Verweisen auf die Antwort von ppinsider. – markets

+1

ich habe es genossen, es zu lesen. danke +1 –

3

Die zusätzliche Größe ist wahrscheinlich wegen der zusätzlichen VTables (http://en.wikipedia.org/wiki/Vtable) durch die virtuellen Klassen und Mehrfachvererbung zugeordnet.

9

Mark Santesson Antwort ist so ziemlich auf das Geld, aber die Geltendmachung, dass es keine vtables falsch. Sie können g ++ -fdump-class-hierarchy verwenden, um anzuzeigen, was vor sich geht.Hier ist der no virtuals Fall:

Class Base 
    size=4 align=4 
    base size=4 base align=4 
Base (0x19a8400) 0 

Class X 
    size=8 align=4 
    base size=8 base align=4 
X (0x19a8440) 0 
    Base (0x19a8480) 0 

Class Y 
    size=8 align=4 
    base size=8 base align=4 
Y (0x19a84c0) 0 
    Base (0x19a8500) 0 

Class Z 
    size=16 align=4 
    base size=16 base align=4 
Z (0x19b1800) 0 
    X (0x19a8540) 0 
    Base (0x19a8580) 0 
    Y (0x19a85c0) 8 
    Base (0x19a8600) 8 

Achten Sie besonders auf das Argument "Basisgröße". Nun ist der virtuals Fall und zeigt nur Z:

Class Z 
    size=20 align=4 
    base size=16 base align=4 
Z (0x19b3000) 0 
    vptridx=0u vptr=((& Z::_ZTV1Z) + 12u) 
    X (0x19a8840) 0 
     primary-for Z (0x19b3000) 
     subvttidx=4u 
    Base (0x19a8880) 16 virtual 
     vbaseoffset=-0x0000000000000000c 
    Y (0x19a88c0) 8 
     subvttidx=8u vptridx=12u vptr=((& Z::_ZTV1Z) + 24u) 
    Base (0x19a8880) alternative-path 

Beachten Sie die „Basisgröße“ ist die gleiche, aber die „Größe“ ist ein Zeiger mehr, und beachten Sie, dass es jetzt ein VTable-Zeiger! Dies wiederum enthält die Konstruktion vtables für die Elternklassen und alle inter Klasse Magie (Bau vtables und virtuelle Tabelle Tabelle (VTT)), wie hier beschrieben:

http://www.cse.wustl.edu/~mdeters/seminar/fall2005/mi.html

Beachten Sie, dass die eigentliche Funktion Versand Vtable wird leer sein.

+0

aber wenn keine der Klassen eine virtuelle Funktion haben, warum die vtable? – wilhelmtell

+0

Führen Sie den Code durch g ++ mit dieser Option, und Sie werden sehen, warum. Schau auf den Link, den ich gegeben habe, um alles zu verstehen. viel besser als ich versuche, es hier wieder zu hacken! – user23167

+0

Was bedeutet "base" in "base size = 16 base align = 4"? Bedeutet es alle Basisklassen? – ibread

Verwandte Themen