多重(菱形)继承编译而不"virtual",但不使用

Multiple (diamond) inheritance compiles without "virtual", but doesn't with

本文关键字:virtual 菱形 继承 编译 多重      更新时间:2023-10-16

给出以下代码(没有虚拟继承):

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

为什么第二段代码不同?

您的第一个场景层次结构对应于:

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

其中D不是抽象的,因为在D类型的对象中有两个A的子对象:一个是B通过B的晶格使其具体化的,另一个是通过c的晶格使其具体化的

除非你试图在D的对象上调用函数F(),否则不会有任何歧义。

第二个场景层次结构对应于:

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

在这个场景中,对象D有一个基类a子对象,它必须覆盖并提供该子对象中纯虚函数的实现。


Herb Sutter在《每周大师》(GOTW)上的文章是多继承的好读物:

  1. 多重继承第一部分
  2. 多重继承第二部分
  3. 多重继承第三部分

对于虚拟继承,D对象只有一个A子对象的基类。这个单独的子对象不能有一个虚函数的两个不同实现。相比之下,没有虚拟继承的D对象有两个不同的基类A子对象,每个子对象都有自己的函数实现(这是可以的,直到您尝试在D对象上调用它,这时您需要指出您想要哪个)。

干杯,hth .