virtuelle Ableitung
-
Hallo Leute
ich bekomme beim Kompilieren folgende Fehlermeldung:error C2512: 'Object::Object' : Kein geeigneter Standardkonstruktor verfuegbar.
für den unten angegebenen Soucecode.
Um den Fehler zubeseitigen, muss ich in der Zeile 40 und 51 noch folgendes angeben:
, Object(c)Das finde ich unpraktisch, denn dafür muss ich nachsehen, ob irgendeine Klasse virtual abgeleitet wurde.
In diesem Fall hab ich Glück und ich bekomme einen Compiler Fehler. Aber Schlimmer wäre es gewesen, wenn die Klasse einen StandardKonstruktor hätte und ich diesen garnicht aufrufen wollte.class Object { public: Object(int c){ printf("Object\n"); } ~Object(){ printf("~Object\n"); } }; class Object1 : public virtual Object { public: Object1(int c):Object(c){ printf("Object1\n"); } ~Object1(){ printf("~Object1\n"); } }; class Object2 : public virtual Object { public: Object2(int c):Object(c){ printf("Object2\n"); } ~Object2(){ printf("~Object2\n"); } }; class Object1_1 : public Object1 { public: Object1_1(int c):Object1(c){ printf("Object1_1\n"); } ~Object1_1(){ printf("~Object1_1\n"); } }; class Object1_2 : public Object1, public Object2 { public: Object1_2(int c):Object1(c), Object2(c){ printf("Object1_2\n"); } ~Object1_2(){ printf("~Object1_2\n"); } };
-
funcky schrieb:
Aber Schlimmer wäre es gewesen, wenn die Klasse einen StandardKonstruktor hätte und ich diesen garnicht aufrufen wollte.
Wenn die Basisklasse einen Standardkonstruktor hat und Du keinen expliziten Konstruktor aufrufst, ruft der Compiler für Dich den Standardkonstruktor auf. Das ist hier genauso wie bei nicht-virtueller Ableitung.
-
Das hab ich schon verstanden.
Mir geht es darum, das ich nicht jedesmal nachsehen möchte, ob die Basis-Klasse irgendwo in seiner Vererbung eine virtuelle Vererbung hat.
Das ist nach meiner Meinung einer Vorprogrammierte Fehlerquelle.
Gibt es eine andere Möglichkeit um sowas zu umgehen ?
-
Mir ist noch nicht ganz klar wo Du die Fehlerquelle siehst. Es wird höchstens ein Konstruktor aufgerufen, den Du nicht aufrufen wolltest, aber das ist sonst auch so.
-
class Object { public: Object(){ a = 0; printf("Object\n"); } Object(int c){ a = c; printf("Object\n"); } ~Object(){ printf("~Object\n"); } void printA(){ printf("Object A=%d\n", a); } int a; }; class Object1 : public virtual Object { public: Object1(int c):Object(c){ printf("Object1\n"); } ~Object1(){ printf("~Object1\n"); } }; class Object2 : public virtual Object { public: Object2(int c):Object(c){ printf("Object2\n"); } ~Object2(){ printf("~Object2\n"); } }; class Object1_1 : public Object1 { public: Object1_1(int c):Object1(c){ printf("Object1_1\n"); } ~Object1_1(){ printf("~Object1_1\n"); } }; class Object1_2 : public Object1, public Object2 { public: Object1_2(int c):Object1(c), Object2(c){ printf("Object1_2\n"); } ~Object1_2(){ printf("~Object1_2\n"); } }; int main(int argc, char* argv[]) { Object1_2 o(5); o.printA(); return 0; }Ergebnis:
Object A=0
an statt:
Object A=5
Deswegen möchte ich nicht, das der falsche Konstruktor aufgerufen wird.
Und das kann ich nur zur Laufzeit feststellen oder ich über prüfe, ob
die Basis Klasse eine virtuelle Vererbung hat.
-
das ist auch nur unerwünscht, weil du zufällig derjenige bist, der Object1 und Object2 implementiert hat. Stell dir vor, Object1 und Object2 hätten folgende konstruktoren:
Object1 (int c) : Object(c*c) {} //... Object2 (int c) : Object(c+c) {} //... Object1_2 (int c) : Object1(c), Object2(c) {} //... Object1_2 o(4); cout << o.a;was ist hier die richtige lösung? 8 oder 16? natürlich nur diese: 0.
hättest du keine virtuelle vererbung, könntest du gar nicht so auf o.a zugreifen, und das problem würde sich gar nicht stellen.
wenn irgendwo virtuelle vererbung mit im spiel ist, *musst* du das einfach wissen, nicht nur wegen der konstruktoren-problematik, sondern überhaupt, um auf das objekt zuzugreifen. für dieses argument musst du dir also schon ein besseres beispiel einfallen lassen.da die deklarationen der klassen übrigens immer verfügbar sind, kannst du auch schon vor der laufzeit überprüfen, ob virtuelle vererbung mit im spiel ist.
-
In diesem Fall muss ich Dir recht geben.
Aber in dem unterem Fall ist doch bekannt, welcher Konstruktor aufgerufen werden soll.
In Zeile 40 soll er den Konstruktor Object(c) und nicht den StandardKonstruktor.class Object { public: Object(){ a = 0; printf("Object\n"); } Object(int c){ a = c; printf("Object\n"); } ~Object(){ printf("~Object\n"); } void printA(){ printf("Object A=%d\n", a); } int a; }; class Object1 : public virtual Object { public: Object1(int c):Object(c){ printf("Object1\n"); } ~Object1(){ printf("~Object1\n"); } }; class Object1_1 : public Object1 { public: Object1_1(int c):Object1(c){ printf("Object1_1\n"); } ~Object1_1(){ printf("~Object1_1\n"); } };
-
funcky schrieb:
In Zeile 40 soll er den Konstruktor Object(c) und nicht den StandardKonstruktor.
Was in der Initialisierungsliste des Object1-CTors steht, ist in diesem Fall völlig egal. Es wird nicht ausgeführt, wenn du ein Objekt einer Unterklasse von Object1 erzeugst. Die am weitesten abgeleitete Klasse ist dafür verantwortlich, die Konstruktoren aller virtuellen Basisklassen aufzurufen. Daran führt kein Weg vorbei.
Was wäre denn, wenn Object2 einen anderen Object-CTor aufrufen würde? Zufall? Oder beide?
-
Ich habs befüchrtet. Danke für Deine Antworten.