虚拟继承使用

pae*_*bal 17 c++ oop inheritance multiple-inheritance

我需要编写一个将由新手和经验丰富的C++开发人员使用的编码约定.动态多态的继承规则如下:

  • 对于动态多态,请考虑使用单继承(树状层次结构),可能具有抽象接口的多重继承
  • 对于继承层次结构(基类等),默认情况下使用公共继承
  • 对于继承抽象接口,默认情况下使用公共虚拟继承

此规则之后将提供有关实施,可能的例外等的详细信息.

所以,问题是这个规则是否适合新手和经验丰富的C++开发人员?(欢迎/利弊,以及来源和链接是受欢迎的)


我看到的是:

优点:

  • 规则易于新手使用,不限制经验丰富的开发人员.
  • 对那些已经熟悉Java/.NET接口的人来说很熟悉
  • 避免与实现的虚拟继承相关的问题(因为它是为抽象接口保留的),以及非虚拟继承(在转换为接口类时可能存在歧义)

缺点:

  • 轻微的性能成本(转换到接口时的速度,虚拟表的大小,类实例中的附加指针)

注意:我已阅读以下在线资源:

注2:在"C++编码标准"第36项中使用Sutter&Alexandrescu后,使用"抽象接口"名称


这是一个应该工作的情况(它的Java/C#等效使用接口工作),但如果接口继承不是虚拟的,那么在C++中就不会这样:

class A
{
   public :
      virtual ~A() = 0 {}
} ;

class B : public A {} ; // should have been virtual to avoid the error
class C : public A {} ; // should have been virtual to avoid the error

class D : public B, public C
{
   public : 
      virtual ~D() {}
} ;

void foo(A * c) {}
void bar(D * d)
{
   foo(d) ; // Error: ambiguous conversions from 'D *' to 'A *
}
Run Code Online (Sandbox Code Playgroud)

是的,显式转换以消除歧义是错误的解决方案(无论如何,显式转换通常是错误的解决方案).

h4u*_*t3r 1

如果您的继承示例不是虚拟的,则它不起作用,因为 c++ 中存在经典的多重继承问题,即死亡钻石。基本上,如果您不指定虚拟继承,每个父类(B,C)都有自己的基 A 对象。这使得对非静态基类函数和变量的所有访问(以及我假设的转换)变得不明确。我无法想象在 C++ 中可以避免这种情况的情况。

编辑:为了记录,这是工作代码:

class A
{
public :
    virtual ~A() {}
};

class B : virtual public A {};
class C : virtual public A {};

class D : virtual public B, virtual public C
{
public :
    virtual ~D() {}
};

void foo(A * c) {}
void bar(D * d)
{
    foo(d);
}

int main(void)
{
    D d;
    foo(&d);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)