Frage an polymorphism, virtual, c++ – Größe der Klassen bei virtueller Vererbung

3

Kann jemand bitte die Größe der Klassen im Fall der virtuellen Vererbung mit virtuellen Funktionen erklären.

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

Die Ausgabe der Klassengröße ist:

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

Der Compiler, den ich benutze, istgcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)

@FredLarson ... Ich weiß über die Größe im Fall von polymorphen Klassen, die vom virtuellen Zeiger betroffen sind, Bescheid ... aber wie wirkt sich die virtuelle Vererbung aus? Gibt es einen versteckten Zeiger, wenn wir virtuell erben? Kundan Kumar
Beachten Sie, dass alle nicht leeren Basis-Unterobjekte korrekt ausgerichtet sein müssen. Sie können also davon ausgehen, dass jede Klasse ein einzelnes 4-Byte-Element hat, das bei 4 ausgerichtet ist, wenn Sie so wollen. Kerrek SB
Fügen Sie die Größe eines vptr zu Ihrer Klassengröße hinzu. Für mehr Details ->stackoverflow.com/questions/1604176/size-of-virtual-pointer-c DumbCoder
Was überrascht Sie an diesen Größen? Fred Larson

Deine Antwort

4   die antwort
6

3 Bytes im Array, 1 Byte Auffüllung, 4 Bytes für den vptr (Zeiger auf die vtable)

sizeof (B): 12

Ein Unterobjekt: 8, 3 Bytes für das zusätzliche Array, 1-Byte-Auffüllung

sizeof (C): 16

Dies ist wahrscheinlich das Überraschende für Sie ... Ein Unterobjekt: 8, 3 Bytes für das zusätzliche Array, 1-Byte-Auffüllung,4 Bytes Zeiger auf A

Wenn Sie über eine virtuelle Vererbung verfügen, ist die Position des Unterobjekts der virtuellen Basis in Bezug auf den Start des vollständigen Typs unbekannt. Daher wird ein zusätzlicher Zeiger zum ursprünglichen Objekt hinzugefügt, um zu verfolgen, wo sich die virtuelle Basis befindet. Betrachten Sie dieses Beispiel:

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

Die Lage derA in Bezug auf den Beginn derB Objekt, wenn der vollständige Typ a istB kann anders sein als der Ort derA Unterobjekt vonB wenn es Teil des endgültigen Objekts istD. Wenn dies nicht offensichtlich ist, nehmen Sie an, dass der relative Standort derselbe ist, und überprüfen Sie, ob der relative Standort vonA in Gedenken anC in einemC endgültiges Objekt oder aC Unterobjekt inD kann auch beibehalten werden.

Was das letzte Beispiel betrifft, habe ich keine Lust, es zu analysieren ... aber Sie können das lesenItanium C ++ ABI für eine konkrete Implementierung des C ++ - Objektmodells. Alle anderen Implementierungen unterscheiden sich kaum.

Letztes Beispiel:

sizeof (D): 32

D enthält ein B-Unterobjekt (12) und ein C-Unterobjekt (16) sowie ein zusätzliches Array der Größe 3 und ein zusätzliches Bit der Polsterung 1.

In diesem speziellen Fall könnte sich die Frage stellen, warum es zwei gibtA Unterobjekte wennC erbt virtuell vonAund die Antwort ist, dass virtuelle Basis bedeutet, dass das Objekt bereit ist, diese Basis mit jedem anderen Typ in der Hierarchie zu teilen, der auch bereit ist, sie zu teilen. Aber in diesem FallB ist nicht bereit zu teilen, es istA Unterobjekt, soC braucht es selbst.

Sie sollten dies verfolgen können, indem Sie den Konstruktoren auf den verschiedenen Ebenen Protokolle hinzufügen. Im Falle vonA Lassen Sie es einen Wert im Compiler annehmen und verschiedene Werte aus jeder Erweiterungsklasse übergeben.

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

Woher:

Die vptrs benötigen jeweils 4 Bytes (64-Bit-Zeiger)Die Char-Arrays benötigen jeweils 4 Bytes (zur Ausrichtung aufgerundet).k ', j' und i 'sind die Kopien der Variablen, die über C und nicht über B vererbt werden.
Ah, richtig, guter Punkt. Edward Loper
C erweitert B nicht, enthält also j nicht. Die zusätzlichen 4 gibt es einen Zeiger auf das Unterobjekt A David Rodríguez - dribeas
0

können Sie den Compliler so einstellen, dass er sie nicht mit #pragma pack (1) im Speicher ausrichtet. Um die aktuellen Packeinstellungen zu speichern und später wiederherzustellen, können Sie auch #pragma pack (push) und #pragma pack (pop) verwenden.

1

sizeof(C) ist mehr alssizeof(B) weil ein Objekt vom Typ C (weil es virtuell von A erbt) einen Zeiger enthält (abgesehen von einem vptr, den auch Objekte vom Typ B enthalten), der auf den Teil von sich selbst zeigt, den es von A geerbt hat. Scott Meyers erklärt dies in Detail (ca. 10 Seiten) in Punkt 24: "Verstehen der Kosten für virtuelle Funktionen, Mehrfachvererbung, virtuelle Basisklassen und RTTI" seines BuchesEffektiveres C ++

Verwandte Fragen