非 Diamond 类型中的虚拟继承

Posted

技术标签:

【中文标题】非 Diamond 类型中的虚拟继承【英文标题】:Virtual inheritance in a non Diamond Type 【发布时间】:2014-05-25 23:36:14 【问题描述】:

当一个类从同一个基类派生的两个类继承时,我无法理解为什么虚拟继承在我们没有遇到类似于钻石问题的问题的情况下有用。

当它仍然有用(或什至需要)时,有人可以给我一个例子或解释吗?

谢谢:)

【问题讨论】:

不存在“钻石问题”。钻石是没有钻石问题的解决方案 有人说钻石吗? @KerrekSB:"diamond problem" is a common term。您可以尝试simple google search,导致***、博客、SO 问题等。“钻石”一词指的是类继承图的形状。除其他外,“问题”一词指的是子对象层次结构缺乏这种形状,以及如何解决对成员函数的调用。简而言之,OP的术语是可以理解的。并且可以谷歌搜索。 【参考方案1】:

当没有潜在的diamond shape inheritance problem 时,虚拟继承并不是很有用。这个问题就是虚拟继承要解决的问题。以奇怪的对象布局和从大多数派生类调用最顶层的基础初始化为代价。

虚拟继承最常见的实际应用是接口。

通过虚拟继承,您可以使用继承实现的Java技术。


在 C++03 中,还有其他虚拟继承用例,基于需要从最派生的类初始化最顶层的类。

这些用例包括:

使类不可继承。 由final 在 C++11 中解决。

强制使用特定的最派生类(模板化)。 在 C++11 中,协变功能(例如 clone 成员函数)可以更轻松地通过中间人继承添加,使用 C++11 构造函数参数转发。

【讨论】:

@JBentley:在接口I 的实现中继承意味着您从I 继承了两次,所以那里有菱形图案。【参考方案2】:

“有用”是一个主观词。它对某些人来说足够有用,因为它是 C++ 中的一个语言特性,但对于其他人来说,它不够用,因为 Java 没有它。接口是类似的东西,但不完成同样的事情。

常见的成语是mixin。您保留常规的类层次结构,但您也从另一个提供一些额外(mixin?)功能的类继承。所以,你不要使用它来让你的类表现得像它的父类,而只是为了实现。

这对我来说似乎很有用。但是,这是主观的。

【讨论】:

【参考方案3】:

是的,在 c++11 之前的时代,virtual 继承对于实现类似final 的机制很有用。

// template style may not work with clang++
template<class T> struct Wrap  typedef T type; ;
template<class Derived> class Final  // no one should inherit `D` from hereon
  Final ()   
  friend class Wrap<Derived>::type;
;

class D : virtual Final<D> ; // `virtual` inheritance
class D2 : public D ;  // if anyone tries to still inherit `D`

int main () 
  D d;
  D2 d2;  // <--- an expected error occurs upon object declaration

请参阅 Bjarne Stroustrup 的页面以获得更简单但有限的方法: Can I stop people deriving from my class?

【讨论】:

以上是关于非 Diamond 类型中的虚拟继承的主要内容,如果未能解决你的问题,请参考以下文章

从具有非虚拟父级的虚拟类继承的正确方法

C ++中的非对称虚拟继承菱形

虚拟继承如何解决“钻石”(多重继承)的歧义?

C++中的继承和纯虚函数

虚拟继承 - 跳过构造函数

这。与基地。对于继承的受保护的非虚拟方法?