Множественное (алмазное) наследование компилируется без "виртуального", но не с
Учитывая следующий код (без виртуального наследования):
class A
{
public:
virtual void f() = 0;
};
class B : public A
{
public:
virtual void f() {}
};
class C : public A
{
public:
virtual void f() {}
};
class D : public B, public C
{
/* some code */
};
int main()
{
D d;
return 0;
}
компиляция кода.
С другой стороны, здесь:
class A
{
public:
virtual void f() = 0;
};
class B : virtual public A
{
virtual void f() {}
};
class C : virtual public A
{
virtual void f() {}
};
class D : public B, public C
{
/* some code */
};
int main()
{
D d;
return 0;
}
Компилятор представляет ошибку компиляции:
no unique final overrider for 'virtual void A::f()' in 'D' .
Почему во втором коде он отличается?
Ответы
Ответ 1
Ваша первая иерархия сценариев соответствует:
F() F()
A A
| |
F() B C F()
\ /
D
Где D не абстрактно, потому что в объекте типа D существуют два подобъекта A: один, который сделан бетоном B через решетку B, а другой, который сделан бетоном через решетку C.
Если вы не попытаетесь вызвать функцию F() на объекте D, не будет никакой двусмысленности.
Вторая иерархия сценариев соответствует:
F()
A
/ \
F() B C F()
\ /
D
В этом случае объект D имеет отдельный объект Sub Base Base, и он должен переопределять и обеспечивать реализацию чистой виртуальной функции в этом подобъекте.
Статьи Herb Sutter в Guru Of The Week (GOTW) - это приятное чтение для множественного наследования:
Ответ 2
С виртуальным наследованием объект D
имеет один подкомпонент базового класса A
. Этот единственный под-объект может иметь две разные реализации виртуальной функции. Напротив, без виртуального наследования объект D
имеет два различных под-объекта базового класса A
, каждый со своей собственной реализацией функции (это нормально, пока вы не попытаетесь вызвать ее на объекте D
, на который указывает, что вам нужно указать, какой из них вы хотите).
Приветствия и hth.