In C++-Klassenhierarchien kann das Diamantproblem auftreten, wenn von einer Basisklasse zwei Nachkommen erben und dann eine weitere Klasse erstellt wird, die von diesen beiden erbt. In diesem Fall enthält das Objekt der abgeleiteten Klasse zwei unabhängige Kopien der Basisklasse. Um dieses Problem zu lösen, wurde in C++ das virtuelle Erben implementiert.
Wenn man herkömmliches Mehrfacherben verwendet:
class A { public: int x; }; class B : public A {}; class C : public A {}; class D : public B, public C {};
Das Objekt D enthält 2 Kopien von A: eine über B, die andere über C. Das führt zu Mehrdeutigkeiten beim Zugriff auf A::x und zu unnötigem Speicherverbrauch.
Virtuelles Erben beseitigt die Duplikation der Basisklasse. Ein Exemplar der Basisklasse A wird von allen Nachkommen verwendet:
class A { public: int x; }; class B : public virtual A {}; class C : public virtual A {}; class D : public B, public C {};
Jetzt enthält D nur eine Kopie von A, und die Mehrdeutigkeit beim Zugriff auf A::x wird beseitigt.
Schlüsselfunktionen:
Warum kann das Diamantproblem nicht durch explizite Pfadangaben über den Gültigkeitsbereich gelöst werden?
Die Gültigkeitsbereichsauflösung löst nur die Mehrdeutigkeit beim Zugriff auf die Mitglieder der Basisklasse, beseitigt jedoch nicht die zusätzlichen Kopien der Basisklasse selbst. Das Problem der doppelten Initialisierung und doppelten Datenspeicherung bleibt bestehen.
In welcher Reihenfolge werden die Konstruktoren beim virtuellen Erben aufgerufen?
Die Konstruktoren der virtuellen Basisklassen werden zuerst und nur einmal aufgerufen, und zwar direkt vom Konstruktor der letzten Klasse in der Erbeshierarchie.
Beispiel:
class A { public: A() { std::cout << "A "; } }; class B : public virtual A { public: B() { std::cout << "B "; } }; class C : public virtual A { public: C() { std::cout << "C "; } }; class D : public B, public C { public: D() { std::cout << "D "; } }; D d; // Ausgabe: A B C D
Muss virtuelles Erben sowohl bei der Deklaration als auch bei der Definition der Klasse angegeben werden?
Ja, virtuelles Erben muss überall angegeben werden, wo von der entsprechenden Basisklasse geerbt wird. Andernfalls ist ein Kompilierungsfehler unvermeidlich, und die Mehrfachvererbung wird zu einer normalen.
Eine komplexe Hierarchie, in der virtuelles Erben nicht angewendet wurde, wodurch im Objekt zwei Kopien der Einstellungen vorhanden sind:
Vorteile:
Nachteile:
Es wurde virtuelles Erben mit einem konsistenten Konstruktor des obersten Nachkommen verwendet:
Vorteile:
Nachteile: