虚拟继承使用

Virtual inheritance use

本文关键字:继承 虚拟      更新时间:2023-10-16

我需要编写一个编码约定,供新手和有经验的C++开发人员使用。动态多态性的继承规则如下:

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

此规则之后将提供有关实现、可能的异常等的详细信息。

因此,问题是:这条规则对于新手和有经验的C++开发人员来说都是可取的吗(欢迎优点/缺点,以及来源和链接)


我看到的是:

优点:

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

缺点:

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

注意:我已经阅读了以下在线来源:

  • 什么时候虚拟继承是一个好的设计
  • http://www.parashift.com/c++-faq-lite/virtual-inheritance-abs.html
  • http://www.artima.com/intv/abcs.html
  • http://cpptips.com/virt_inher2
  • http://g.oswego.edu/dl/mood/C++AsIDL.html

注2:";抽象接口";这个名字是以Sutter&Alexandrescu在";C++编码标准";


这是一种应该有效的情况(它使用接口的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 *
}

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

你知道吗?你已经给出了问题中的所有重要信息。我看不出任何技术层面的答案。显然,其他人也没有看到你发布的内容有任何重大的技术问题。

不过,我会回答你大胆的问题:,它既适合新手也适合专业人士。

  • 新手有一些有用的技术指南
  • Pros可以做他们想做的事情,如果他们能给出一个理由的话,因为你用"考虑"answers"默认"来限定你的规则,所以基本上没有人会说你必须这样做,因为你的规则的措辞已经允许例外

由于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;
}

您的第一条规则完全排除class D

对于动态多态性,考虑使用单一继承(树状层次结构),可能使用抽象接口的多重继承

你的规则很好。

那么,你的问题是什么呢?现在剩下什么?