2012-05-10 14 views
18
class A { 
     int i; 
public: 
     A() {cout<<"in A's def const\n";}; 
     A(int k) {cout<<"In A const\n"; i = k; } 
     }; 

class B : virtual public A { 
public: 
     B(){cout<<"in B's def const\n";}; 
     B(int i) : A(i) {cout<<"in B const\n";} 
     }; 

class C : public B { 
public: 
     C() {cout<<"in C def cstr\n";} 
     C(int i) : B(i) {cout<<"in C const\n";} 
     }; 

int main() 
{ 
     C c(2); 
     return 0; 
} 

Der Ausgang ist in diesem FallOrder of Konstruktoraufruf in virtuelle Vererbung

in A's def const 
in B const 
in C const 

Warum dies nicht in der Eingabe in A const

`Es sollte die Reihenfolge von 1 arg Konstruktoraufruf folgen. Aber was passiert tatsächlich bei der Ableitung von B aus A mit virtuellen Schlüsselwort.

Es gibt einige Frage

Auch wenn ich das Schlüsselwort virtual in oben Programm entfernen und entfernen Sie alle Standardkonstruktors es Fehler gibt. Also, warum es den Def-Konstruktor benötigt

Antwort

13

Die Konstruktoren für virtuelle Basisklassen werden immer von der am weitesten abgeleiteten Klasse mit allen Argumenten aufgerufen, die sie übergeben könnte. In Ihrem Fall spezifiziert die abgeleitete Klasse keinen Initialisierer für A, so wird der Standardkonstruktor verwendet.

+1

@james .... du meinst zu sagen, dass die am weitesten abgeleitete Klasse hier C C sollte den Initialisierer für A angeben. Aber beim Entfernen Ein Standardkonstruktor und Hinzufügen von C (int i): A (i), B (i) in Cs Konstruktor funktioniert es nicht – Kunal

+0

@MikeDeSimone ... ya ich habe das selbe geschrieben, aber A's Standard-Konstruktor entfernt, aber ich bekomme Kompilierungsfehler ... können Sie bitte erklären, warum das so ist..und wie man vorsichtig ist, wenn ich habe eine komplexe Vererbung in. – Kunal

+0

@Kunal: Ja, ich habe meinen Kommentar gelöscht, weil Sie es tatsächlich versucht haben. Also hier haben wir eine Antwort, abgestimmt, die nicht funktioniert. @James, bitte erkläre, wie man den Code repariert, damit der 'A (int)' -Konstruktor aufgerufen wird. –

5

Als JamesKanze has explained, im Falle von virtual Vererbung ist es die am weitesten abgeleitete Klasse, die den Konstruktor der virtuellen Basisklasse aufruft. Wenn Sie also den Konstruktor A haben möchten, der den Aufruf einer Ganzzahl erfordert, müssen Sie diese zur Initialisierungsliste C hinzufügen.

C(int i) : A(i), B(i) {cout<<"in C const\n";} 

Für den zweiten Teil Ihrer Frage, werden Standardkonstruktoren nicht erforderlich, aber dann explizit die abgeleitete Klasse muss die Nicht-Standard-Konstruktor aufrufen, da der Compiler für Sie, dies zu tun in Abwesenheit eines nicht in der Lage ist Nicht-Standardkonstruktor.

#include <iostream> 
using namespace std; 

class A { 
    int i; 
public: 
    // A() {cout<<"in A's def const\n";}; 
    A(int k) {cout<<"In A const\n"; i = k; } 
}; 

class B : virtual public A { 
public: 
    // B(){cout<<"in B's def const\n";}; 
    B(int i) : A(i) {cout<<"in B const\n";} 
}; 

class C : public B { 
public: 
    C() : A(42), B(42) {cout<<"in C def cstr\n";} 
    C(int i) : A(i), B(i) {cout<<"in C const\n";} 
}; 

int main() 
{ 
    C c(2), c2; 
    return 0; 
} 

Dieser druckt

In A const 
in B const 
in C const 
In A const 
in B const 
in C def cstr 
+0

@praetorian ... danke für deine antwort. Aber ich bin immer noch unklar mit einer Sache .... warum ist es notwendig, C(): A (42), B (42) gibt es ?? Bitte klären Sie – Kunal

+2

@Kunal Jeder abgeleitete Klassenkonstruktor (für Nicht-POD-Typen) muss seinen Basisklassenkonstruktor initialisieren. Wenn Sie den Basiskonstruktor nicht explizit auflisten, ruft der Compiler den Standardkonstruktor für Sie auf. Wenn kein solcher Standard-Basiskonstruktor vorhanden ist, müssen Sie einen vorhandenen Basiskonstruktor explizit aufrufen. – Praetorian

+0

heißt das, dass A() zweimal aufgerufen wird? Was passiert mit dem Aufruf von A() in B()? – Youda008

2

hier draußen Es gibt zwei Fragen.

Warum tritt dies nicht in A const ein?

Da Sie virtuelle Vererbung verwenden.

Wenn Sie virtuelle Vererbung verwenden, die Initialization list of most-derived-class's ctor directly invokes the virtual base class's ctor.. In diesem Fall bedeutet dies, dass der Konstruktor C den Konstruktor Adirekt aufruft. Da Sie nicht angegeben haben, welcher A-Konstruktor in der Initialisierungsliste C aufgerufen werden soll, wird der Standardkonstruktor aufgerufen.

C(int i) : A(i), B(i) {cout<<"in C const\n";} 

Wenn ich das Schlüsselwort virtual in oben Programm zu entfernen und entfernen Sie alle Standardkonstruktors es Fehler gibt:

wird durch die Änderung der Implementierung von C::C(int) an diesem fixiert. Warum braucht es also den Konstruktor def ?

Da B spezifiziert auch nicht, welche A Ctor zu nennen, so dass der Standard-Konstruktor verwendet wird.Wenn Sie A s def ctor entfernen, kann B nicht kompiliert werden.