Mehrfachvererbung. Seltsames Verhalten
-
Hallo.
In meinem Design habe ich unter anderem eine Mehrfachvererbung. Ich weiß sollte man möglichst nicht anwenden. Scheint mir in diesem Fall aber trotzdem angebracht zu sein.
Also hier mein Beispielcode: Habe den von einem Tutorial aus dem Netz. Etwas nach meinem Fall abgeändert.
class UltimateBase { private: int value; public: UltimateBase(int value) : value(value) {} }; class Base1 : virtual public UltimateBase { public: Base1(int value) : UltimateBase(value) {} }; class Base2 : virtual public UltimateBase { public: Base2() : UltimateBase(-1) {} }; class Derived : public Base1, public Base2 { public: Derived(int value) : Base1(value), Base2() {} }; int main() { Derived d(3); }
So nun durch die virtuelle Vererbung wird ja meine oberste Basisklasse nur 1 mal initialisiert. Und da Base1 zuerst UltimateBase initialisiert wird diese mit dem Wert 3 initialisiert. Der Wert -1 der von Base2 kommt wird ja dann ignoriert. Sollte so doch eigentlich richtig sein.
Beim Kompilieren erhalte ich dann allerdings einen Fehler:
'UltimateBase::UltimateBase': Kein geeigneter Standardkonstruktor verfügbar.
Und das hier im Beispiel in der Zeile 30.Wer versucht den den Standardkonstruktor von UltimateBase aufzurufen. Ich verstehs nicht??!!
-
Hallo.
Hat keiner eine Erklärung?
-
Hmm genaueres könnte ich jetzt nicht sagen. Definier doch mal einen Standardconstructor und schau im Debugger wer den ruft. Ggf hilft das schonmal weiter.
So nun durch die virtuelle Vererbung wird ja meine oberste Basisklasse nur 1 mal initialisiert. Und da Base1 zuerst UltimateBase initialisiert wird diese mit dem Wert 3 initialisiert. Der Wert -1 der von Base2 kommt wird ja dann ignoriert. Sollte so doch eigentlich richtig sein.
Das scheint nicht ganz richtig zu sein:
http://www.mycplus.com/tutorials/cplusplus-programming-tutorials/multiple-inheritance/5/ORDER OF MEMBER INITIALIZATION
The order of member initialization may seem a bit strange, but it does follow a few simple rules. The order of member initialization does not follow the order given by the initialization list, but another very strict order over which you have complete control. All inherited classes are initialized first in the order they are listed in the class header. If lines 14 and 15 were reversed, class new_date would still be initialized first because it is mentioned first in line 8. It has been mentioned that C++ respects its elders and initializes its parents prior to itself. That should be a useful memory aid in the use of member initializers.
Next, all local class members are initialized in the order in which they are declared in the class, not the order in which they are declared in the initialization list. Actually, it would probably be good practice to not use the member initializer to initialize class members but instead to initialize them in the normal constructor code.
Finally, after the member initializers are all executed in the proper order, the main body of the constructor is executed in the normal manner.
Obwohl das meines erachtens noch nicht das Problem erklärt.
-
Schau dir mal (vor allem das Diagram) an
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9Edit: soll bedeuten die virtuelle Basis Klasse muss von der untersten Klasse initialisiert werden.
-
Edit: soll bedeuten die virtuelle Basis Klasse muss von der untersten Klasse initialisiert werden.
Versteh ich nicht ganz. Wie sieht es dann richtig aus?
-
@ihoernchen danke für den Link. Dann ists auch kein Wunder das er den Constructor anmeckert.
class Derived : public Base1, public Base2 { public: Derived(int value) : UltimateBase(value),Base1(value), Base2() {} };
Hier wäre es also besser wenn Base1 und Base2 gar keinen Constructor von UltimateBase aufrufen.
-
Dann ist doch aber auch das Tutorial falsch von dem ich das ganze abgeschaut habe: