Speicherlayout bei Mehrfachvererbung
-
Hallo zusammen,
gibt es ein standardmäßiges Speicherlayout für Objekte mit Mehrfachvererbung?Zum Beispiel bei folgender Situation
class A { public: A() : i(23) {} int i; }; class B { public: B() : j(42) {} int j; }; class C : public A, public B { public: C() : k(1) {} int k; };ist dann bei
C* c = new C(); A* a = c; B* b = c;gesichert, dass a==c und nicht etwa b==c
(ist ja wichtig für anschließendes delete),
oder ist das compilerabhängig?Vielen Dank schonmal...
C14PS: Was auch noch interessant wäre: Was passiert, wenn eine der Klassen virtuelle Funktionen enthält, wo ist dann der Zeiger auf die vtable gespeichert?
-
Wenn der Destruktor der Basisklasse virtuell ist, kannst du das gesamte Objekt mit einem Zeiger auf die Basisklasse zerstören, ohne dir andere Gedanken machen zu müssen.
-
sicher?
Der Destruktor wird zwar richtig aufgerufen, aber es sollte meiner Meinung nach Probleme mit der Speicherverwaltung geben, da die Adresse bei new nicht mit der von delete übereinstimmt.
-
Schau mal hier:
http://tutorial.schornboeck.net/virtual.htm
-
ok, mit virtuellem Destruktur funktionierts tatsächlich, delete ist schlauer als ich dachte.
Allerdings wäre es natürlich schön, wenn es auch ohne gehen würde (ich schreib ne library und das B ist ne user-Klasse, da will ich den virtuellen Destruktur eigentlich nicht fordern)
Aber zur Not gehts natürlich auch so, thx!
-
C14 schrieb:
ok, mit virtuellem Destruktur funktionierts tatsächlich, delete ist schlauer als ich dachte.
Allerdings wäre es natürlich schön, wenn es auch ohne gehen würde (ich schreib ne library und das B ist ne user-Klasse, da will ich den virtuellen Destruktur eigentlich nicht fordern)
Aber zur Not gehts natürlich auch so, thx!Der virtuelle Destruktor ist lediglich bei der Basisklasse erforderlich. Das heisst, dass der User die einfach ableiten kann, ohne selbst in der geerbten Klasse den Destruktor virtuell setzen zu müssen. (Es sei denn sie fungiert selbst wieder als Baisklasse).
-
Ok, ich habe mir mal wieder zu viel Zeit beim Schreiben gelassen und bin 2mal überholt worden.
Hier kommt die Antwort trotzdem:C14 schrieb:
gibt es ein standardmäßiges Speicherlayout für Objekte mit Mehrfachvererbung?
Das Layout ist implementierungsabhängig. Es gibt zwar ein paar Regeln, die befolgt werden müssen, spielen aber in Deinem Fall keine Rolle.
C14 schrieb:
Zum Beispiel bei folgender Situation
class A { public: A() : i(23) {} int i; }; class B { public: B() : j(42) {} int j; }; class C : public A, public B { public: C() : k(1) {} int k; };ist dann bei
C* c = new C(); A* a = c; B* b = c;gesichert, dass a==c und nicht etwa b==c
a==c liefert true (c wird vor dem Vergleich implizit zu A* kontertiert)
b==c liefert true (c wird vor dem Vergleich implizit zu B* kontertiert)
Trotzdem kann man nicht erwarten, dass beivoid* va = a; void* vb = b; void* vc = c; bool ac = (va==vc); bool bc = (vb==vc); bool ab = (va==vb);alle boolschen Variablen mit dem Wert true initialisiert werden. Falls A und B beide nicht leer sind, ist
absicherlich false. Ebenso mindestens eine der beiden anderen (ac, cb).C14 schrieb:
(ist ja wichtig für anschließendes delete),
Wichtig ist nur, dass der Destruktor der Basisklasse virtuell ist, wie drakon schon gesagt hat. Also A muss einen virtuellen Destruktor haben, falls Du über "delete a;" das Objekt löschen willst. Genauso muss B einen virtuellen Destruktor haben, wenn Du das Objekt über "delete b;" löschen willst. Das muss auch bei Einfachvererbung so sein, damit der richtige Destruktor aufgerufen wird und damit auch alle Elemente der abgeleiteten Klasse (zB ein std::string oder so) ordnungsgemäß zerstört werden.
Die wegen Mehrfachvererbung eventuell nötige "Anpassung" der Zeiger passiert mit virtuellen Destruktoren automatisch und ist Sache des Compilers.
Gruß,
SP
-