Множественное (алмазное) наследование компилируется без «виртуального», но не с - PullRequest
12 голосов
/ 28 августа 2011

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

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' . 

Чем отличается во втором коде?

Ответы [ 2 ]

9 голосов
/ 28 августа 2011

Ваша первая иерархия сценариев соответствует:

    F()   F()
     A     A
     |     |
 F() B     C F()
      \   /
        D 

Где D не является абстрактным, потому что есть два подобъекта A в объекте типа D: тот, который сделан конкретным посредством B через решетку Bи другой, который сделан конкретным через решетку C.

Если вы не попытаетесь вызвать функцию F () для объекта D, не будет никакой двусмысленности.

Ваша вторая иерархия сценариевсоответствует:

       F()  
        A
      /   \
 F() B     C F()
      \   /
        D  

В этом сценарии объект D имеет единственный подобъект Базового класса A, и он должен переопределить и обеспечить реализацию чисто виртуальной функции в этом подобъекте.


Статьи Херба Саттера в Guru Of Week (GOTW) являются хорошим чтением для множественного наследования:

  1. множественное наследование, часть I
  2. Часть II с множественным наследованием
  3. Часть III с множественным наследованием
7 голосов
/ 28 августа 2011

При виртуальном наследовании объект D имеет единственный подобъект базового класса A. Этот единственный подобъект не может иметь две разные реализации виртуальной функции. Напротив, без виртуального наследования объект D имеет два отдельных подобъекта базового класса A, каждый со своей собственной реализацией функции (что нормально, пока вы не попытаетесь вызвать его для объекта D, в какой момент вам нужно указать, какой вы хотите).

Ура & hth.

...