9

Вопрос по c++ – Виртуальное наследие и страшный бриллиант

Я испытываю трудности с проблемой ужасного бриллианта. Для напоминания, вот классическая иерархия классов этой проблемы:

    B
   / \
 C1   C2
   \ /
    D

Чтобы решить эту проблему, стандартное решение состоит в том, чтобы заставить C1 и C2 использовать виртуальное наследование для наследования от B.

My problem is that B and C1 are from an SDK that I cannot modify. Пример ниже, где я не могу сделатьSubClassB наследовать практически от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

В такой ситуации, когдаSubClassB нельзя изменить для использования виртуального наследования отBase, Как что должно так, что:

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).

Любой намек?

More info to answer comments

Моя целевая архитектура немного сложнее, чем образец, который я привел в исходном вопросе:

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

LeafOne: наследуется от SubClassA и SubClassB (SDK)

LeafTwo: наследуется от SubClassA и SubClassC (SDK)

LeafThree: наследуется от SubClassA и 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. Этот класс не будет создан, но именно здесь можно обрабатывать LeafOne, LeafTwo и LeafThree одним и тем же при выполнении некоторой обработки.

Потому что на самом деле мне нужно иметь 3 разных класса Leafs, все они наследуются от разных подклассов SDK (все они подклассы «Base»). Я отредактировал оригинальный пост (в конце для уточнения).

от Marc

Зачем тебе это нужно? Вы думали о шаблонах?

от sje397

Почему вы так думаетеSubClassA должен наследовать отBase совсем? Учитывая определениеSubClassB очевидно, чтоBase не предназначен для виртуального базового класса в иерархии, которая включает в себяSubClassB.

от CB Bailey

Как насчет одного класса, унаследованного и другого составного.

от iammilind

Это то, что я рассматриваю, но интеграция такого Leaf Class не будет такой элегантной в нашем SDK, и придется решать множество различных проблем. Тем не менее, вы правы, это один из способов решения этой проблемы, но я хотел бы найти способ сделать это через наследование для облегчения интеграции с функциями SDK.

от Marc
2 ответа
1

Если вы действительно застряли с этими конструктивными ограничениями

я бы определенно обратился к подклассам из B напрямую с классом, который взял C1 и C2 в качестве составных компонентов. К сожалению, это требует ручного зеркалирования их интерфейса (надеюсь, он небольшой или вы можете ограничить его тем, что вам нужно) и проксирования через субкомпоненты. Это не очень красиво, но если вы не можете применить какие-то ограничения на дизайн в другом месте, то у вас не останется большого выбора.

Один недостаток, конечно, состоит в том, что у вас нет идентификатора типа, который вы ищете (подкласс не удовлетворит "isa" из C1 или C2), которого может быть достаточно, чтобы выбросить этот подход из воды.

Это не красиво. Но я ожидаю, что с учетом ваших ограничений это может быть "наименее плохим" решение.

4

Это указывает на проблему с вашим дизайном

для которой самый простой ответavoid the diamond на первом месте. Ваш выбор имен для примера кода достаточно плох, чтобы затруднить рассуждение о том, что вы на самом деле хотели бы сделать, но, во всяком случае, пересмотреть,need наследовать от обоих родителей, и имеет ли это смысл.

Наследование является одной из наиболее часто используемых конструкций в ОО-языках, оно решает проблему, но используется какзолотой молот где-либо еще. Много раз, что у вас в рукевинт, не гвоздь и правильный инструмент не молоток.

Error: User Rate Limit Exceeded

от Marc

Error: User Rate Limit Exceeded

от 

Похожие вопросы