11

我很难解决可怕的钻石问题。提醒一下,这里是这个问题的经典类层次结构:

    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中定义的纯虚拟函数并在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' 中的虚拟基础'Base' 不可访问如果我取消注释此调用:我收到此错误:对成员'f_PureVirtualBase' 的请求不明确
  • 如果我在这个调用前面加上类名(myleaf.SubClassA::f_PureVirtualBase() 那么它可以工作,但显然有问题,因为叶子 对象中包含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。

4

2 回答 2

4

这表明您的设计存在问题,最简单的答案是首先避免使用钻石。您为示例代码选择的名称非常糟糕,以至于很难推断您可能真正想要做什么,但无论如何,请重新考虑您是否需要从父母双方继承,以及这是否有意义。

继承是 OO 语言中最常被滥用的结构之一,它确实解决了一个问题,但它在其他任何地方都被用作金锤。很多时候,你手中的东西是螺丝,而不是钉子,正确的工具也不是锤子。

于 2012-04-05T12:09:21.850 回答
1

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

当然,一个缺点是你没有你正在寻找的类型标识(子类不会满足 C1 或 C2 的“isa”),这可能足以让这种方法被淘汰。

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

于 2012-04-05T13:34:14.023 回答