11

I am having a hard time with a dreaded diamond problem. For a reminder, here is the classical class hierarchy of this problem:

    B
   / \
 C1   C2
   \ /
    D

To solve it, the standard solution is to make C1 and C2 use virtual inheritance to inherit from B.

My problem is that B and C1 are from an SDK that I cannot modify. Example below where I cannot make SubClassB inherit virtually from Base. Classes: PureVirtualBase, Base and SubClassB are from the SDK I use. I cannot modify them. SubClassA and Leaf are my custom classes. I can change them.

     PureVirtualBase(SDK)
           |
        Base(SDK)
       /        \
 SubClassA   SubClassB(SDK)
       \        /
          Leaf

In such a situation where SubClassB cannot be changed to use virtual inheritance from Base. How what should so that:

  • Leaf instance only contains one Base
  • Avoid the ambiguity when trying to access functions defined pure virtual in PureVirtualBase and implemented in 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();
}
  • If I comment the call to f_PurevirtualBase it compiles but I have a warning that virtual base 'Base' inaccessible in 'Leaf' due to ambiguity If I uncomment this call: I get this error : request for member 'f_PureVirtualBase' is ambiguous
  • If I prefix this call by the class name (myleaf.SubClassA::f_PureVirtualBase() then it works, but something is obviously wrong as there are 2 Base contained in the Leaf Object).

Any hint?

More info to answer comments

My target architecture is slightly more complex that the sample I provided in the original question:

 PureVirtualBase(SDK)
       |
     Base(SDK)
        |
        --SubClassA
        --SubClassB(SDK)
        --SubClassC(SDK)
        --SubClassD(SDK)

LeafOne : inherits from SubClassA and SubClassB(SDK)

LeafTwo : inherits from SubClassA and SubClassC(SDK)

LeafThree : inherits from SubClassA and SubClassD(SDK)

SubClassA is my own private code. It provides custom functions. It should be able to be treated like a Base instance by SDK methods. This class won't be instantiated but it is here to be able to handle LeafOne, LeafTwo and LeafThree in the same when performing some treatment.

4

2 に答える 2

4

これは、デザインに問題があることを示しています。最も簡単な答えは、最初からダイヤモンドを避けることです。サンプル コードの名前の選択は、実際に何をしたいのかを判断するのを難しくするほど悪いものですが、いずれにせよ、両方の親から継承する必要があるかどうか、またそれが理にかなっているかどうかを再検討してください。

継承は OO 言語で最も乱用されている構造の 1 つであり、問​​題を解決しますが、他のあらゆる場所で黄金のハンマーとして使用されます。多くの場合、手に持っているのは釘ではなくネジであり、正しいツールはハンマーではありません。

于 2012-04-05T12:09:21.850 に答える
1

これらの設計上の制約に本当に行き詰まっている場合は、C1 と C2 を複合コンポーネントとして使用するクラスを使用して、B から直接サブクラス化することを検討します。残念ながら、それには手動でインターフェイスをミラーリングし (小さいか、必要なものに制限できることを願っています)、サブコンポーネントにプロキシする必要があります。それはきれいではありませんが、他の場所でデザインにいくらかのギブを強制できない限り、実際には多くの選択肢が残されていません.

もちろん、1 つの欠点は、探している型 ID がないことです (サブクラスは C1 または C2 の「isa」を満たさない)。これは、このアプローチを水から吹き飛ばすのに十分な場合があります。

それはきれいではありません。しかし、あなたの制約を考えると、それが「最も悪い」解決策になると思います。

于 2012-04-05T13:34:14.023 に答える