2015-05-15 21 views
10

Rozważmy kodWielokrotne dziedziczenie klasy niejednoznaczne baza

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() {} 

kompilator (g ++ 5.1) ostrzega, że ​​

ostrzeżenie: bezpośredni baza 'Base' niedostępne w 'B' powodu niejednoznaczności struct B: public A, public Base{};

Rozumiem to, Base jest duplikowane w B.

  1. Dlaczego nie ma ostrzeżenie dla C? Czy C nie dziedziczy po A i Derived, które dziedziczą po Base?

  2. Dlaczego dodanie virtual

    struct Derived: virtual Base{}; 
    

wyniki teraz w obu B i C emitujących ostrzeżeń, żyją na Wandbox

ostrzeżenia: bezpośredni bazę 'Base' niedostępnych w 'B' powodu niejednoznaczności struct B: public A, public Base{};

ostrzeżenie: bezpośredni baza 'Base' niedostępne w 'C' powodu niejednoznaczności struct C: public A, public Derived{};

+0

wyszukiwarka internetowa dla „strasznych diamentowej dziedziczenia”. –

+0

@ThomasMatthews Wiem, czym jest problem z diamentem i jest to ściśle związane z tym, dlaczego 'B' ostrzega. Jednak nie rozumiem, dlaczego "C" jest w porządku. – vsoftco

+0

Myślę, że to tylko przypadek, w którym gcc nie wykrywa niejednoznaczności w 'C', ponieważ' Base' * jest * niejednoznaczny w tym przypadku.Kiedy wirtualnie wywodzisz się z 'Base', najbardziej pochodna klasa (' C') jest odpowiedzialna za wywołanie konstruktora 'Base', a więc gcc ponownie wykrywa niejednoznaczność. – Praetorian

Odpowiedz

2

W B, że to niemożliwe, aby odnieść się do członków Base podobiektu dziedziczona bezpośrednio. Rozważmy:

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 
    } 
}; 

W C to nie jest problem. Oba x „s mogą być określane za pomocą kwalifikowanych nazw:

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

Więc dostaniesz ostrzeżenie to taki, który ma sens tylko wtedy, gdy baza bezpośredni również dziedziczone przez inną ścieżkę.

Dla twojego drugiego pytania nie mogłem odtworzyć ostrzeżenia z C na Coliru z g ++ - 5.1.

2

Brak sposoby jednoznacznie Dostęp do członków bazy w „B”, podczas gdy jest to możliwe w „C”, jak pokazano w poniższym kodzie:

#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; 
}