C++ 我们可以在菱形继承模式中只使用一个虚拟继承吗?
假设我有一些类:C++ 我们可以在菱形继承模式中只使用一个虚拟继承吗?,c++,C++,假设我有一些类:Base,Derived1,Derived2,…等等。所有派生类都派生自Base。现在,我想为所有派生类添加一些功能,但不能修改这些类。因此,我提出了以下方法: 使用虚拟继承创建一个类,如下所示: class Additional: virtual public Base { void f() { //some codes operating on class Base } }; 然后我可以通过以下方式扩展每个派生类: class MyDeriv
Base
,Derived1
,Derived2
,…等等。所有派生类都派生自Base
。现在,我想为所有派生类添加一些功能,但不能修改这些类。因此,我提出了以下方法:
使用虚拟继承创建一个类,如下所示:
class Additional: virtual public Base {
void f() {
//some codes operating on class Base
}
};
然后我可以通过以下方式扩展每个派生类:
class MyDerived1: public Derived1, public Additional {};
然而,当我搜索互联网时,似乎在钻石继承的情况下,我们必须对这两个类Derived1
和Additional
使用虚拟继承。因此,上述方法将不起作用。因此,我的问题是:
- 为什么我们必须在菱形继承案例中使用两个虚拟继承
- 如果我的方法无效,是否有其他方法可以解决上述困难
template<class BaseT>
class Additional: public BaseT {
void f() {
//some codes operating on class Base
}
};
using MyDerived1 = Additional<Derived1>;
模板
附加类:公共BaseT{
void f(){
//一些在类基上运行的代码
}
};
使用MyDerived1=附加值;
现在,我想为所有派生类添加一些功能
您可以编写自由函数
void some_functionality(Base & base)
{
...
}
为什么我们必须在菱形继承案例中使用两个虚拟继承
这里有两个问题。为什么我们需要使用虚拟继承呢
- 虚拟继承具有运行时成本。假设您正在将指向
的指针或引用转换为指向Derived1
的指针或引用。使用普通的固有特性,只需要添加一个在编译时已知的固定数值偏移量(该偏移量通常为零,因此根本没有成本!)。对于虚拟继承,您必须经历某种指针间接寻址。这种转换发生在可能不明显的地方,例如,无论何时调用在基类上定义的方法,都是隐式进行的。大多数类都没有利用这种虚拟继承,所以它们都要为此付出代价是没有意义的Base
- 如果您从
和Derived1
继承,而在Derived2
上没有虚拟继承,那么您将得到两个类型为Base
的子对象。有时候这就是你想要的!如果C++总是给你虚拟继承,即使你不要求它,那么你将失去这个能力。Base
virtual
”?换句话说,当我们以后创建另一个类时,为什么我们不能在一段代码中重写一个使用非虚拟继承的决定呢
-
部分是因为C++中编译的工作原理。如果
Derived1
实际上从Base
继承,那么这将影响所有Derived1
对象,甚至是那些不属于附加
的对象。(必须是这样,因为引用Derived1
的函数不知道它是否是附加
的一部分。)您建议您的Additional
的定义回到Derived1
的定义中,并将其含义更改为虚拟继承-即使在不包含头文件的编译单元中李>
D1
、D2
和D3
,其中D1
非虚拟继承自Base
,而D2
和D3
虚拟继承自Base
。然后您将得到两个Base
子对象:一个用于D1
,另一个在D2
和D3
之间共享。诚然,这是非常不寻常的,但这可能是你想要的,而且你的建议会阻止它使用模板的解决方案非常棒。我只有一个小小的疑问:在编译后,函数f()是否会在extecucable文件中的多个派生类中多次出现?@zbh2047-可能会。然而,另一方面,如果它足够简单,它可能根本不会出现。模板也倾向于内联。“菱形继承模式”没有一个正式的定义,大多数关于它的文章都是肤浅的。