C++ 虚拟基类是一种可行的或有用的特性吗

C++ 虚拟基类是一种可行的或有用的特性吗,c++,class,virtual,C++,Class,Virtual,我知道存在虚拟基类机制来防止“钻石”问题。但我很好奇,是否通过重新设计类层次结构来更好地处理这种情况。 以下面的案例为例: 我看到的这个机制现在存在的问题是,你需要能够预测有人将从B和C继承。所以,这并不意味着我们最好用虚拟标记每个继承 类a的虚拟继承意味着 A必须在最派生的类中初始化,并且 对A事物的访问效率有所降低(因为A子对象可以在多个派生类对象之间共享,因此可以在每个派生类对象中处于动态偏移) 由于这些原因,使用虚拟继承时需要谨慎 一个很好的经验法则是对接口使用虚拟继承,而不是对实现

我知道存在虚拟基类机制来防止“钻石”问题。但我很好奇,是否通过重新设计类层次结构来更好地处理这种情况。 以下面的案例为例:


我看到的这个机制现在存在的问题是,你需要能够预测有人将从B和C继承。所以,这并不意味着我们最好用虚拟标记每个继承

a
的虚拟继承意味着

  • A
    必须在最派生的类中初始化,并且
  • A
    事物的访问效率有所降低(因为
    A
    子对象可以在多个派生类对象之间共享,因此可以在每个派生类对象中处于动态偏移)
由于这些原因,使用虚拟继承时需要谨慎


一个很好的经验法则是对接口使用虚拟继承,而不是对实现类使用虚拟继承

  • A
    必须在最派生的类中初始化,并且
  • A
    事物的访问效率有所降低(因为
    A
    子对象可以在多个派生类对象之间共享,因此可以在每个派生类对象中处于动态偏移)
由于这些原因,使用虚拟继承时需要谨慎


一个很好的经验法则是对接口使用虚拟继承,而不是实现类。

你可以在
虚拟成员函数上提出同样的观点——为什么不让所有成员函数
虚拟呢?因为如果有人从你的
类继承了
,他们可能喜欢覆盖你的成员函数。我们之所以不这样做,是因为对于
virtual
基类,
virtual
成员函数具有与之相关的额外成本(时间/资源开销和复杂性)

你可以在
virtual
成员函数上提出同样的观点——为什么不让所有成员函数
virtual
呢?因为如果有人从你的
类继承了
,他们可能希望能够覆盖你的成员函数。我们之所以不这样做,是因为对于
virtual
基类,
virtual
成员函数具有与之相关的额外成本(时间/资源开销和复杂性)

虚拟继承是所有具有多重继承功能的语言中的必备功能。虽然所有继承案例都可能是虚拟的,但这有:

  • 额外费用
  • 并非总是预期的结果
这是因为虚拟继承是继承的一种特殊情况,其中继承的是类的直接派生指令,而不是类本身。结果,派生另一个类的每个基类实际上都将这个虚拟基类作为直接基类提供给下一个派生类。当然,如果多个基类提供相同的虚拟基类,则会导致一次由派生类派生,但这是因为这些多个基类提供多个派生指令,但只提供一个类(与正常继承不同,在这种情况下,基类将提供基类的多个子对象)

它始终是一个直接基类这一事实的结果是要求在每个下一个派生类中显式构造它。当然,默认构造函数规则适用,但是C++在这个规则中甚至没有结果——基类初始化虚基类的代码被接受;唯一被拒绝的情况是当虚拟基类在多个基类中“竞争性初始化”时——在这种情况下,您必须通过提供构造规范来“解决冲突”

请不要因为蹩脚的自我推销而揍我,但我已经在这里更详细地描述了这个主题:


虚拟继承是所有具有多重继承功能的语言中的必备功能。虽然所有继承案例都可能是虚拟的,但这有:

  • 额外费用
  • 并非总是预期的结果
这是因为虚拟继承是继承的一种特殊情况,其中继承的是类的直接派生指令,而不是类本身。结果,派生另一个类的每个基类实际上都将这个虚拟基类作为直接基类提供给下一个派生类。当然,如果多个基类提供相同的虚拟基类,则会导致一次由派生类派生,但这是因为这些多个基类提供多个派生指令,但只提供一个类(与正常继承不同,在这种情况下,基类将提供基类的多个子对象)

它始终是一个直接基类这一事实的结果是要求在每个下一个派生类中显式构造它。当然,默认构造函数规则适用,但是C++在这个规则中甚至没有结果——基类初始化虚基类的代码被接受;唯一被拒绝的情况是当虚拟基类在多个基类中“竞争性初始化”时——在这种情况下,您必须通过提供构造规范来“解决冲突”

请不要因为蹩脚的自我推销而揍我,但我已经在这里更详细地描述了这个主题:


是的,我们可以这样做。我的问题是这样问的。但这将是混乱的,很难阅读代码。从C和D继承应该可以很好地工作。A(但不是wrt C)。类A实际上是在两个链中继承的。子对象中只有一个。但是,是的,这是对必须由inhe高层做出决定的机制的有效批评
class A { public: void Foo() {} };
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};