Многоуровневый базовый класс множественного наследования
Рассмотрим код
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
.
-
Почему нет предупреждения для C
? Не наследует C
как от A
, так и от Derived
, которые оба наследуют от Base
?
-
Зачем добавлять virtual
struct Derived: virtual Base{};
теперь выводится как в сообщениях B
, так и C
, нажимая на Wandbox
предупреждение: прямая база 'Base'
недоступна в 'B'
из-за двусмысленности struct B: public A, public Base{};
предупреждение: прямая база 'Base'
недоступна в 'C'
из-за двусмысленности struct C: public A, public Derived{};
Ответы
Ответ 1
В 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
могут ссылаться на использование квалифицированных имен:
struct C: public A, public Derived {
void foo() {
int& x1 = A::x; // OK
int& x2 = Derived::x; // OK
}
};
Таким образом, вы получите предупреждение, которое имеет смысл только тогда, когда прямая база также наследуется по другому пути.
Для вашего второго вопроса я не смог воспроизвести предупреждение с помощью C
на Coliru с g++ - 5.1.
Ответ 2
Нет никаких способов однозначного доступа к элементам Base в "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 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;
}