2015-05-15 6 views
10

Si consideri il codiceereditarietà multipla classe base ambiguo

struct Base{}; 
struct Derived: public Base{}; 

struct A: public Base{}; 

struct B: public A, public Base{}; 

struct C: public A, public Derived{}; // why no ambiguity here? 

int main() {} 

Il compilatore (g ++ 5.1) avverte che

avvertimento: di base diretta 'Base' inaccessibili in 'B' a causa dell'ambiguità struct B: public A, public Base{};

Capisco, Base è duplicato in B.

  1. Perché non c'è nessun avvertimento per C? C non eredita sia da A sia da Derived, che entrambi ereditano da Base?

  2. Perché aggiungendo virtual

    struct Derived: virtual Base{}; 
    

risultati ora in entrambe le B e C avvertimenti che emettono, in diretta su Wandbox

avvertimento: di base diretta 'Base' inaccessibili in 'B' a causa dell'ambiguità struct B: public A, public Base{};

avvertimento: base diretta 'Base' inaccessibili in 'C' causa dell'ambiguità struct C: public A, public Derived{};

+0

ricerca su Internet per "eredità diamante temuto". –

+0

@ThomasMatthews So qual è il problema del diamante, ed è strettamente correlato al perché "B" dà un avvertimento. Comunque quello che non capisco è perché 'C' è OK. – vsoftco

+0

Penso che sia solo un caso di gcc che non rileva l'ambiguità in 'C' perché' Base' * è * ambiguo anche in questo caso.Quando derivate virtualmente da 'Base' la classe più derivata (' C') è responsabile per chiamare il costruttore 'Base', e così gcc inizia a rilevare di nuovo l'ambiguità. – Praetorian

risposta

2

In B, è impossibile riferirsi ai membri del Base subobject ereditato direttamente. Considerare:

struct Base { 
    int x; 
}; 

struct B: public A, public Base { 
    void foo() { 
     int& x1 = A::x; // OK 
     int& x2 = x; // ambiguous 
     // no way to refer to the x in the direct base 
    } 
}; 

Nel C questo non è un problema. Entrambi x 's possono essere indicati con nomi qualificati:

struct C: public A, public Derived { 
    void foo() { 
     int& x1 = A::x; // OK 
     int& x2 = Derived::x; // OK 
    } 
}; 

Quindi l'avvertimento che si ottiene è quello che ha senso solo quando una base diretta è anche ereditato attraverso un altro percorso.

Per la seconda domanda, non è stato possibile riprodurre l'avviso con C su Coliru con g ++ - 5.1.

2

ci sono modi per accedere in modo inequivocabile ai membri di base in "B", mentre è possibile in "C", come illustrato nel codice seguente:

#include <iostream> 

using namespace std; 

struct Base 
{ 
    void print() 
    { 
     cout << "Base" << endl; 
    } 
}; 

struct Derived : public Base {}; 

struct A : public Base 
{ 
    void print() 
    { 
     cout << "A" << endl; 
    } 
}; 

struct B : public A, public Base 
{ 
    void print() 
    { 
     A::print(); 

     //error (ambiguous), no way to access to Base::print => warning 
     //Base::print(); 
    } 
}; 

struct C : public A, public Derived 
{ 
    void print() 
    { 
     A::print(); 
     Derived::print(); // Not Ambiguous, it's the Base inherited by 'Derived' which is used. 
     // Still an error but you can access print indirectly through "Derived" => no warning needed 
     //Base::print(); 
    } 
}; 

int main() 
{ 
    B b; 
    b.print(); 

    C c; 
    c.print(); 

    return 0; 
}