2016-04-05 4 views
2

Dies scheint nicht C++ 11 arbeiten in:C++ Delegieren Ctor und Eltern Ctor mit dem Argument

class B : public A 
{ 
    public: 
    B(const A& a) 
     : A(a) // parent constructor for passing the parameter 
     , B() // delegating constructor for init of other members 
    {}; 
    // ... 
}; 

gcc sagt mir, dass an initializer for a delegating constructor must appear alone.

Wie kann ich den Konstruktor der Elternklasse mit dem Parameter aufrufen und den Basiskonstruktor der B-Klasse aufrufen? (Ich habe eine Reihe anderer Konstruktoren in B, die das gleiche Verhalten benötigen).

Momentan überlege ich, eine private B::init()-Funktion zu schreiben und sie in allen Konstruktorfirmen zu verwenden, aber das schmeckt ein bisschen viel von C++ 03.

Was ist die bevorzugte Lösung?

+1

Warum nicht in die andere Richtung schreiben? 'B :: B(): B (A {}) {}' und 'B :: B (const A & a): A (a), anderes_Member {} {}'. – Jarod42

+0

@ Jarod42 Warum nicht eine Antwort anstelle eines Kommentars schreiben? – Barry

+1

@Barry: Nicht sicher Wenn ich etwas nicht vermisse. – Jarod42

Antwort

5

Ich glaube, die bevorzugte Art der Delegierung ist umgekehrt, es ist nicht gedacht, um allgemeine Teile von Konstruktoren zu refaktorieren, sondern um den einfacheren als einen Spezialfall eines komplexeren Falles zu definieren.

Sie sollten also mit B(const A& a) starten und dies als Delegierungsziel verwenden.

class B : public A 
{ 
    public: 
    B() : B(A()); 
    B(const A& a) : A(a) // parent constructor for passing the parameter 
    {}; 
}; 

Sie rufen A() sowieso, wenn B zu schaffen.

Das Grundprinzip dahinter ist, wenn Sie zwei "teilweise spezialisierte" c'tors haben, könnten Sie sie nicht verwenden, um das komplexe zu initialisieren. ZB:

class B : public A 
{ 
    public: 
    B() {}; 
    B(int) : B() {}; 
    B(double) : B() {}; 
    B(double,int) : B(int), B(double) {}; // can't do it. 
}; 

Ich glaube, dass der technische Grund in Bathshebas Antwort erklärt wird. Schauen Sie, was passieren würde, wenn Sie einen gemeinsamen Teil in B() haben:

class B : public A 
{ 
    public: 
    B() {}; 
    B(int) : B() {}; 
    B(double) : B() {}; 
    B(double,int) : B(int), B(double) {}; //ooops would get B() called twice! 
}; 

Es ist der Diamant Problem von Vererbung bekannt. Die Lösung besteht darin, die Logik umzukehren.

class B : public A 
{ 
    public: 
    B() : B(0,0) {}; 
    B(int a) : B(a,0) {}; 
    B(double d) : B(0,d) {}; 
    B(double a, int d) {/*full implementation*/}; 
}; 
+0

Plus eine für die Bereitstellung einer Lösung, im Gegensatz zu meiner Antwort ;-) – Bathsheba

+1

Sieht aus wie ein Plagiat von Barrys Kommentar = /. Aber ich habe angefangen, es zu schreiben, bevor es gepostet wurde. – luk32

+0

Meiner Ansicht nach ist das nicht schädlich: Kommentare sind der schlechte Cousin einer Antwort, da erstere nicht so leicht von Experten begutachtet werden können, und es gibt keinen Akzeptanzmechanismus. – Bathsheba

2

B(const A& a) : A(a), B() macht keinen Sinn, da B() wird auch die Basisklasse A initialisieren. Das wäre im Wesentlichen eine doppelte Initialisierung, was ein inhärenter Widerspruch ist.

Die einzige echte Option für die Sprache ist, nichts anderes zu erlauben, wenn Sie einen delegierten Konstruktor verwenden. Das sagt dir dein Compiler.

+0

Absolut nicht. – Bathsheba

+0

Sorry, Kommentar entfernt. – Gauthier

+0

Es ist also ein Konflikt, weil 'B()' 'A()' aufruft, aber dann versuche ich * auch * A (a) 'zu nennen, richtig? – Gauthier