Множественное (алмазное) наследование компилируется без "виртуального", но не с

Учитывая следующий код (без виртуального наследования):

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.