这是尝试了解使用虚拟基类继承的影响,尤其是关于运行时成本。我想到的情况还涉及接口(或 ABC )。
I----------
/ | \ |
D1 D2 D3 Isub
| /
D3Dec
因此,我们有一个接口I
,我们有不同的实现D1
,D2
和D3
。但现在的问题是,有一个特殊的装饰器,它只包含一些(任意)I
实现,然后根据通过I
表达的合同添加扩展功能。
因此,从逻辑或设计视角开始,需要通过从Isub
派生的子接口I
表达扩展能力。因此,任何Isub
自动也会履行I
合同。
现在,要在C ++中实现此类,接口I
的任何实现必须完成virtual
,同样,Isub
必须继承virtual
来自I
,否则我们最终会在I
中找到两个D3Dec
子对象。
I
的每个实现必须通过棘手的虚拟基本偏移调整来支付内存布局的价格。正确的吗?I
和Isub
都是纯虚拟的情况,即没有成员,只有纯虚函数?那么它是否有可能在没有实际继承的情况下完成这项工作?Isub
的引用。如果客户端调用扩展功能,他们实际上会在D3Dec
内调用所述功能的实现,而这又会使用其他I
- 功能来实现扩展功能,因为显然D3dec
对具体I
- 它装饰的实现一无所知。这是否必然意味着我们必须使用虚拟继承?或者是否有任何基于模板的技巧来解决这个问题,但仍然有一个(抽象的)子接口Isub
?显而易见的替代方案当然是切断I
和Isub
之间的联系,将其变成一个微不足道的混合体。这很有效,但很难看,因为Isub
本身没有多大意义,独立于I
。两者甚至在签名等上使用相同的数据类型......
答案 0 :(得分:2)
通过使接口类成为具体类的模板参数,可以完全避免钻石继承问题。然后不再需要虚拟类继承。
class I { ... };
template<class Ifc>
class D3Impl : public Ifc
{ ... };
typedef D3Impl<I> D3;
class Isub : public I { ... };
class D3Dec : public D3Impl<Isub>
{ ... };