虚拟继承和可怕的钻石

时间:2012-04-05 10:39:44

标签: c++ multiple-inheritance virtual-inheritance diamond-problem

我遇到了一个可怕的钻石问题。 提醒一下,这是这个问题的经典类层次结构:

    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 的虚拟继承的情况下。怎么应该这样:

  • Leaf 实例仅包含一个 Base
  • PureVirtualBase 中尝试访问定义为pure virtual的函数并在 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的调用,它会编译,但我有一个 警告说 虚拟基础'基础'由于歧义而在'Leaf'中无法访问如果我取消注释此调用:我收到此错误:请求成员 'f_PureVirtualBase'含糊不清
  • 如果我通过类名称为此调用添加前缀 (myleaf.SubClassA :: f_PureVirtualBase()然后它可以工作,但有些东西 显然是错误的,因为 Leaf 中包含2个 Base 对象)。

任何提示?

回复评论的更多信息

我的目标架构比原始问题中提供的示例稍微复杂一些:

 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。

2 个答案:

答案 0 :(得分:4)

这表明您的设计存在问题,最简单的答案是首先避免钻石。您为示例代码选择的名称已经足够严重,难以说明您可能实际想要做什么,但无论如何都要重新考虑您是否需要从父母双方继承,以及是否这是有道理的。

继承是OO语言中滥用最多的构造之一,它确实解决了一个问题,但在其他地方用作golden hammer。很多时候,你手上的东西是screw,而不是钉子,正确的工具不是锤子。

答案 1 :(得分:1)

如果您真的遇到这些设计约束,我肯定会直接从B中继承一个将C1和C2作为复合组件的类。不幸的是,这需要手动镜像他们的界面(希望它很小,或者你可以将它限制为你需要的)并代理到子组件。它不漂亮,但除非你能在其他地方强制执行一些设计,否则你真的没有多少选择。

当然,一个缺点是你没有你正在寻找的类型标识(子类不满足C1或C2的“isa”),这可能足以将这种方法从水中吹走。

这不漂亮。但我希望,鉴于你的限制,它可能是“最不好”的解决方案。