虚拟继承和可怕的钻石
Virtual Inheritance and dreaded diamond
我遇到了一个可怕的钻石问题。提醒一下,这里是这个问题的经典类层次结构:
B
/
C1 C2
/
D
为了解决这个问题,标准的解决方案是让C1和C2使用虚拟继承来继承B.
我的问题是B和C1来自一个我无法修改的SDK下面的示例中,我无法使SubClassB从Base虚拟继承。类:PureVirtualBase、Base和SubClassB来自我使用的SDK。我不能修改它们。SubClassA和Leaf是我的自定义类。我可以改变它们。
PureVirtualBase(SDK)
|
Base(SDK)
/
SubClassA SubClassB(SDK)
/
Leaf
在SubClassB无法更改为使用Base的虚拟继承的情况下。如何应该这样:
- 叶实例只包含一个基
- 尝试访问在PureVirtualBase中定义的纯虚拟函数和在Base
class PureVirtualBase
{
public:
PureVirtualBase()
{
cout<<"<<PureVirtualBase::PureVirtualBase" << endl;
cout<<">>PureVirtualBase::PureVirtualBase" << endl;
}
virtual int f_PureVirtualBase()=0;
};
class Base : public PureVirtualBase
{
public:
Base(std::string id) {
cout<<"<<Base::Base:"<<id << endl;
m_id=id;
cout<<">>Base::Base:"<<m_id << endl;
}
virtual int f_PureVirtualBase() {
cout<<"Base::f_PureVirtualBase" << endl;
return 1;
}
private:
std::string m_id;
};
class SubClassA: public virtual Base
{
public:
SubClassA(): Base("From SubClassA") {
cout<<"<<SubClassA::SubClassA" << endl;
cout<<">>SubClassA::SubClassA" << endl;
}
};
class SubClassB: public Base
{
public:
SubClassB():Base("From SubClassB") {
cout<<"<<SubClassB::SubClassB" << endl;
cout<<">>SubClassB::SubClassB" << endl;
}
};
class Leaf: public SubClassA, public SubClassB
{
public:
Leaf():SubClassA(), SubClassB(), Base("From Leaf") {
cout << "<<Leaf::Leaf" << endl;
cout << ">>Leaf::Leaf"<< endl;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Leaf myleaf;
myleaf.f_PureVirtualBase();
return a.exec();
}
- 如果我对f_PurevirtualBase的调用进行注释,它会编译,但我有一个警告由于歧义,虚拟基"base"在"Leaf"中不可访问如果我取消注释此调用:我会收到此错误:请求成员"f_PureVirtualBase"不明确
- 如果我在这个调用前面加上类名(myleaf.SubClassA::f_PureVirtualBase()那么它是有效的,但有些东西显然是错误的,因为叶中包含2个基对象)
有什么提示吗?
回答评论的更多信息
我的目标体系结构比我在最初的问题中提供的示例稍微复杂一些:
PureVirtualBase(SDK)
|
Base(SDK)
|
--SubClassA
--SubClassB(SDK)
--SubClassC(SDK)
--SubClassD(SDK)
LeafOne:继承自SubClassA和SubClassB(SDK)
LeafTwo:继承自SubClassA和SubClassC(SDK)
LeafThree:继承自SubClassA和SubClassD(SDK)
SubClassA是我自己的私有代码。它提供自定义功能。SDK方法应该能够将其视为一个Base实例这个类不会被实例化,但它在这里可以在执行某些处理时同时处理LeafOne、LeafTwo和LeafThree。
这表明您的设计有问题,对此最简单的答案是首先避免菱形。您为示例代码选择的名称太糟糕了,很难推断您实际想要做什么,但无论如何,请重新考虑您是否需要从父母双方继承,以及这是否有意义。
继承是OO语言中最受滥用的构造之一,它确实解决了一个问题,但在其他任何地方都被用作金锤。很多时候,你手里拿的是螺丝钉,而不是钉子,正确的工具也不是锤子。
如果你真的被这些设计约束所困扰,我肯定会直接从B中用一个将C1和C2作为复合组件的类进行子类化。不幸的是,这需要手动镜像他们的接口(希望它很小,或者你可以将其限制在你需要的范围内),并代理到子组件。它并不漂亮,但除非你能在其他地方对设计做出一些让步,否则你就没有太多选择了。
当然,一个缺点是你没有你想要的类型标识(子类不满足C1或C2的"isa"),这可能足以让这种方法失效。
它不漂亮。但我认为,考虑到您的限制,这可能是"最不坏"的解决方案。
- 钻石继承虚拟成员铸造与指针
- 接口的钻石继承(C++)
- c++ 中的函数重载如何在没有钻石继承的情况下工作?
- C++解决没有虚拟继承的钻石继承问题
- 如何调用所有基本类的复制构造函数,以在C 中复制钻石继承中最派生的类对象
- 假设钻石继承打破了C++的封装是否正确?
- C++多个钻石继承和纯虚函数
- 首选钻石继承中一个类的变量
- 钻石继承,C++ 处理
- 将 Boost.Serialization 直接与虚拟钻石继承一起工作
- 钻石继承最低基类构造函数
- 钻石继承方案在 G++ 中编译良好,但在 VC++/Eclipse 中产生警告/错误
- C++ "triangle"(而非钻石)继承
- 让钻石继承发挥作用,但Eclipse仍然抱怨
- 钻石继承与提升::绑定
- 为什么不使用只有一个虚拟继承的钻石继承呢
- 使用 Windows V2 凭据提供程序的钻石继承
- c++虚拟/非虚拟钻石继承
- 带有混合继承修饰符(protected/private/public)的钻石继承
- 避免钻石继承