9

У меня трудное время с проблемой страшного алмаза. Для напоминания, здесь иерархия классического класса этой проблемы:Виртуальное наследование и страшный бриллиант

B 
/\ 
C1 C2 
    \/
    D 

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

Моей проблемы заключается в том, что B и C1 являются SDK, которые я не могу изменить. Пример ниже, где я не могу сделать SubClassB Наследовать практически от База. Классы: PureVirtualBase, Base и SubClassB - из используемого SDK. Я не могу их изменить. SubClassA и Leaf - мои пользовательские классы. Я могу их изменить.

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

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

  • Leaf экземпляр содержит только один Base
  • Избегайте двусмысленности при попытке доступа к функциям определяется чисто виртуальным в PureVirtualBase и реализован в базе
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 компилирует, но у меня есть предупреждение, что виртуальная база «База» недоступна в «Лист» из-за неоднозначности Если я раскомментировать этот вызов: Я получаю эту ошибку: запрос для члена ' f_PureVirtualBase»неоднозначен
  • Если я префикс этого вызова по имени класса (myleaf.SubClassA :: f_PureVirtualBase(), то она работает, но что-то , очевидно, не так, как есть 2 Base содержится в Leaf Объект).

Подсказка?

Более подробную информацию, чтобы ответить на комментарии

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

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

+6

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

+2

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

+0

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

ответ

4

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

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

+0

Я думаю, вы просто попали в точку. В конце я использовал ваш совет и изменил нашу иерархию классов. – Marc

+0

Вы сказали, что этот молот + шутка тоже вчера, не так ли: p? – Liviu

1

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^