2015-05-15 1 views
10

Рассмотрим кодМножественное наследование неоднозначным базовый класс

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

компилятор (G ++ 5.1) предупреждает, что

предупреждение: прямая база 'Base' недоступна в 'B' из-за неоднозначности struct B: public A, public Base{};

Я понимаю это, Base дублируется в B.

  1. Почему нет предупреждений для C? Не C наследует и от A, и от Derived, которые оба наследуют от Base?

  2. Почему добавление virtual

    struct Derived: virtual Base{}; 
    

результатов в настоящее время в обоих B и C испускающего предупреждения, живет на Wandbox

предупреждения: прямое основание 'Base' недоступного в 'B' из-за неоднозначности struct B: public A, public Base{};

предупреждение: прямая база 'Base' недоступна в 'C' из-за неоднозначности struct C: public A, public Derived{};

+0

Поиск Интернет для «страшном алмазным наследство». –

+0

@ThomasMatthews Я знаю, что такое проблема с алмазами, и это тесно связано с тем, почему «B» дает предупреждение. Однако я не понимаю, почему 'C' в порядке. – vsoftco

+0

Я думаю, что это просто случай, когда gcc не обнаруживает двусмысленность в 'C', потому что' Base' * is * неоднозначный в этом случае тоже.Когда вы фактически выходите из 'Base', самый производный класс (' C') отвечает за вызов конструктора 'Base', и поэтому gcc снова начинает обнаруживать неоднозначность. – Praetorian

ответ

2

В B, это невозможно передать членам Base подобъекте унаследовал непосредственно. Рассмотрим:

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

В C это не проблема. Оба x «s может быть отнесен к использованию квалифицированных имен:

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

Так предупреждение вы получите один, что имеет смысл только когда прямая база также наследуется через другой путь.

Для вашего второго вопроса я не смог воспроизвести предупреждение с C на Coliru с g ++ - 5.1.

2

Там нет способа однозначно доступа к членам базы в «B», а это возможно в «C», как показано в следующем коде:

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