5

Im folgenden Code fordert der Compiler die Basis Klasse X als default construcible an. Allerdings, wenn ich entfernen Sie das virtuelle Schlüsselwort aus dem Erbe der Klasse Node, den Zugangs zum Mitglied m_x wird, natürlich, nicht eindeutig, aber die Standardkonstruktors für Klasse X ist nicht mehr erforderlich .Erzwingt die virtuelle Vererbung, dass eine Basisklasse standardmäßig konstruierbar ist?

Was ist der Grund dafür?

#include <iostream> 

struct Apply 
{ 
    template< typename T > 
    struct Node : virtual T // this line contains the virtual inheritance 
    { 
     template< typename ...Args> 
     Node(Args... args) 
      : T(args...) 
     {} 
    }; 

    template < typename ...BaseClasses> 
    struct Inheritance; 

    template < typename FirstBaseClass, typename ...OtherBaseClasses> 
    struct Inheritance< FirstBaseClass, OtherBaseClasses... > : FirstBaseClass 
      , Inheritance<OtherBaseClasses...> 
    { 
     template< typename ...Args> 
     Inheritance(Args... args) 
      : FirstBaseClass(args...) 
      , Inheritance<OtherBaseClasses...>(args...) 
     { 

     } 
    }; 
}; 

template < > 
struct Apply::Inheritance< > 
{ 
    template< typename ...Args> 
    Inheritance(Args... args){} 
}; 

struct X 
{ 
    X(int i){} 

    int m_x; 
}; 

struct A : Apply::Node<X> 
{ 
    A(int i) 
     : Apply::Node<X>(i) 
     , m_a(i) 
    { 

    } 
    int m_a; 
}; 


struct B : Apply::Node<X> 
{ 
    B(int i) 
     : Apply::Node<X>(i) 
     , m_b(i) 
    { } 

    int m_b; 
}; 

struct C : Apply::Node<X> 
{ 
    C(int i) 
     : Apply::Node<X>(i) 
     , m_c(i) 
    { } 

    int m_c; 
}; 

struct Example : Apply::Inheritance< A, B, C > 
{ 
    Example(int i) 
     : Apply::Inheritance< A, B, C >(i) 
    { } 

    void print() const 
    { 
     // this line needs the virtual inheritance 
     std::cout << m_x << std::endl; 

     std::cout << m_a << std::endl; 
     std::cout << m_b << std::endl; 
     std::cout << m_c << std::endl; 
    } 
}; 

int main() 
{ 
    Example ex(10); 

    ex.print(); 

    return 0; 
} 
+0

Dies ist kaum ein * minimal * Beispiel. Ich kann ungefähr 100 Zeilen Code von hier ausschneiden! – Barry

+0

@Barry sorry dafür, aber ich denke, das einzige überflüssige Ding, um das Beispiel gültig zu halten, ist die Basisklasse C. Ich hoffe, der Code ist klar, auch wenn es ein bisschen länger als das Minimum ist. – nyarlathotep108

+1

Nur 'A',' X' und 'Knoten ' ist ausreichend (brauchen nicht 'Apply',' Vererbung', 'B',' C', oder 'Beispiel' ...) – Barry

Antwort

0

Ausgehend von @Berry Antwort, war die einzige Möglichkeit, den Code zu beheben, einen expliziten Aufruf an den virtuellen geerbten X Konstruktor zu codieren.

Allerdings ist es nicht genug, um explizit den Bau von X in Klassen nennen A, B oder C: es ist im Grunde in der Vererbung auf jeder Ebene in jede Klasse beteiligt genannt werden muß!

Die knifflig war die Inheritance <> variadische Template-Klasse: jeder Schritt der variadische Expansion der expliziten Aufruf der X-Konstruktor bereitstellen muss.

Hier ist der Code, der auf MinGW 4.9 funktioniert.2 mit aktiviertem C++ 11 Flag:

#include <iostream> 

template< typename T, typename V > 
struct Node : virtual V 
{ 
    using Virtual = V; // Added this line 

    template< typename ...Args > 
    Node(Args... args) 
     : V(args...) 
    { } 
}; 

template < typename ...BaseClasses> 
struct Inheritance; 

template < typename FirstBaseClass, typename ...OtherBaseClasses> 
struct Inheritance< FirstBaseClass, OtherBaseClasses... > 
     : FirstBaseClass 
     , Inheritance<OtherBaseClasses...> 
{ 
    template< typename ...Args> 
    Inheritance(Args... args) 
     : FirstBaseClass::Virtual(args...) // added this line 
     , FirstBaseClass(args...) 
     , Inheritance<OtherBaseClasses...>(args...) 
    { } 
}; 

template < > 
struct Inheritance< > 
{ 
    template< typename ...Args > 
    Inheritance(Args... args) 
    { } 
}; 

struct X 
{ 
    X(int i) 
     : m_x(i) 
    { } 

    int m_x; 
}; 

struct A : Node< A, X > 
{ 
    A(int i) 
     : X(i) // added this line 
     , Node< A, X >(i) 
     , m_a(i) 
    { } 

    int m_a; 
}; 


struct B : Node< B, X > 
{ 
    B(int i) 
     : X (i) // added this line 
     , Node< B, X >(i) 
     , m_b(i) 
    { } 

    int m_b; 
}; 

struct C : Node< C, X > 
{ 
    C(int i) 
     : X (i) // added this line 
     , Node< C, X >(i) 
     , m_c(i) 
    { } 

    int m_c; 
}; 

struct Example : Inheritance< A, B, C > 
{ 
    Example(int i) 
     : X (i) // added this line 
     , Inheritance< A, B, C >(i) 
    { } 

    void print() const 
    { 
     // this line needs the virtual inheritance 
     std::cout << m_x << std::endl; 

     std::cout << m_a << std::endl; 
     std::cout << m_b << std::endl; 
     std::cout << m_c << std::endl; 
    } 
}; 

int main() 
{ 
    Example ex(10); 

    ex.print(); 

    return 0; 
} 
5

Die Initialisierung Bestellung für eine Klasse wie das geht [class.base.init]:

In einem nicht delegieren Konstruktor Initialisierung erfolgt in folgenden Reihenfolge:
- Erste und Nur für den Konstruktor der am weitesten abgeleiteten Klasse (1.8) werden virtuelle Basisklassen in in der Reihenfolge initialisiert, in der sie auf einer Tiefen-links-nach-rechts-Traversierung des gerichteten azyklischen Graphen der Basisklassen stehen, wobei "left-to -right "ist die Reihenfolge des Auftretens der Basisklassen in der abgeleiteten Klasse base-specifier-li st.

Ihre Hierarchie ist A --> Node<X> --> X, so das erste, was initialisiert zu erhalten, ist die X, da es sich um eine virtuelle Basisklasse ist. Es wird angegeben in Ihrem mem-initializer, so die implizite Standardkonstruktion eingefügt:

A(int i) 
    : X() // <== implicit 
    , Node<X>(i) 
    , m_a(i) 
{ 

} 

Da X nicht standardmäßig konstruierbar, können Sie diese Fehlermeldung erhalten. Sie können dieses Problem beheben, mit nur ausdrücklich das Richtige bereitstellt:

A(int i) 
    : X(i) 
    , Node<X>(i) 
    , m_a(i) 
{ 

Sie müssen zweimal gebaut keine Sorge über X werden, da virtuelle Basisklassen nur für die meisten abgeleiteten Klasse konstruiert sind, ... die wäre A und nicht Node<X>.

+0

Dies ist immer noch funktioniert nicht für mich. Ich fügte den expliziten X (i) -Konstruktoraufruf in A, B, C und sogar in Beispiel hinzu, aber der Compiler fragt mich immer noch nach einem Standard-Konstrukt X. – nyarlathotep108

+0

@ nyarlathotep108 Beachten Sie, dass Ihre 'Vererbung ' von 'A' und abgeleitet ist 'Vererbung ' - aber es stammt auch virtuell von 'X' - so muss es auf seiner Initialisierungsliste Konstruktion von' X' haben. Einfaches Sprechen Ihre 'Vererbung' Klassenvorlage ist nicht für den Umgang mit virtueller Vererbung gedacht ... – PiotrNycz

+0

@PiotrNycz Ich habe den Code korrigiert, jetzt ist die virtuelle Vererbung korrekt implementiert – nyarlathotep108