2016-11-17 16 views
1

Для проекта я хочу скрыть некоторые детали реализации из интерфейса библиотеки. Единственный способ, которым я столкнулся с этим «эффективным» (с точки зрения кодирования и обслуживания), заключался в множественном наследовании абстрактных и конкретных базовых классов на основе одной и той же абстрактной базы. Итак, да, я закончил с расширенной структурой алмазов.C++ множественное наследование/виртуальное наследование

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

В основном мне нужно предоставить несколько «инструментов». Эти «инструменты» имеют, конечно, некоторые детали реализации, которые я хочу скрыть с помощью интерфейсных ABC, например:

класс Tool1Impl: public ITool1;

класс Tool2Impl: public ITool2;

Однако, конечно, инструменты имеют довольно общие черты.

Поэтому я хотел бы иметь общий базовый класс, но детали реализации снова должны быть скрыты через интерфейсы.

я придумал следующее (алмаз) схеме:

  ITool           
     / | \    
     / |  \ 
    /  |  \ 
ITool1 ToolImplBase ITool2 ... IToolN 
    \  / \ /
    \ /  \ /
    \ /  \/
    ToolImpl1  ToolImpl2 ... IToolImplN 

ToolImplBase реализует чистую виртуальную функциональность ITool. ToolImpl1 реализует чистую виртуальную функциональность, объявленную в ITool1.

план реализации выглядит следующим образом:

class ITool { 
public: 
    virtual int common_foo(int a) = 0; 
}; 

class ITool1 : public virtual ITool { 
public: 
    virtual int specific_foo(int b) = 0; 
}; 

class ITool2 : public virtual ITool { 
public: 
    virtual int specific_bar(int c) = 0; 
}; 

class ToolImplBase : public virtual ITool { 
public: 
    virtual int common_foo(int a) override; 
protected: 
    int _some_common_data; 
}; 

class ToolImpl1 : public ToolImplBase, public virtual ITool1 { 
public: 
    virtual int specific_foo(int b) override; 
private: 
    int _some_specific_data; 
}; 

class ToolImpl2 : public ToolImplBase, public virtual ITool2 { 
public: 
    virtual int specific_bar(int c) override; 
private: 
    int _some_specific_data; 
}; 

кажется, делать то, что я хочу, но я не уверен, если есть какие-либо потенциальные проблемы или очевидные проблемы с этим. Я также не уверен, правильно ли я получил «виртуальные» в схеме наследования (а не виртуальные методы, но «общедоступный виртуальный»). Одна проблема в том, что MSVC (я застрял с 2010 из-за некоторых внешних depencies в это время) дает мне предупреждение компилятора C4250:

warning C4250: 'ToolImpl1': inherits'ToolImplBase::ToolImplBase::common_foo' via dominance 

Могу ли я просто игнорировать это? Я даже не уверен, почему я получаю это, потому что непримиримый способ «common_foo» является чисто виртуальным, поэтому на самом деле не существует допустимой «недоминирующей» реализации.

Спасибо за любой вход (для «никогда использования И.Р.», за исключением, я стараюсь избегать его, где это возможно, уже).

+1

Мой маленький кусочек: не стесняйтесь использовать MI, когда это требуется, но если у вас есть алмаз, то вы, вероятно, на ложном пути. Вы уверены, что не используете наследование из-за результатов вместо смысла? Две вещи, которые следует учитывать для ToolImplBase (я не могу сказать больше, потому что пример вымышленный): состав и частное наследование. –

+0

Пример не в том, что вымышленный, это из моего фактического кода, конечно, упрощенного. Как бы вы использовали композицию здесь? Просто делегирование всех общих функций из ITool в ToolImplFoo в содержащуюся ToolImplBase? –

+0

Функция 'common_foo' C4250 наследуется по 2 пути и имеет разную реализацию, ее необходимо реализовать в окончательной форме. – Danh

ответ

0

Существует несколько объяснений по поводу предупреждения в здесь: What does C4250 VC++ warning mean?

Я думаю, что нет никаких проблем с вашим кодом, потому что вы предназначены ITool1 в качестве интерфейса.

Если вы реализуете common_foo функцию в ITool1, вы не знаете, какой реализация common_foo будет работать при создании ToolImpl1.

Вы будете внимательны к проблеме, но кто-либо еще может юридически реализовать функцию common_foo в IToolX реализации без повышения ошибки.

Мой последний комментарий: зачем вам нужен ITool1, который будет получен из ITool? ToolImpl1 уже получен из ToolImplBase, поэтому ваш фактический класс реализации всегда будет выводиться из ITool.

Я хотел бы изменить IToolX интерфейс, как показано ниже

class IToolX{ 
    public: 
    virtual int specific_foo(int b) = 0; 
}; 
+0

Спасибо, я понял C4250 в целом, но не в этом специальном случае, потому что он фактически не реализован в пути «Интерфейс». - Что касается вашего вопроса: я хочу, чтобы ITool1 был получен из ITool, потому что, как я уже сказал, я хочу скрыть данные об использовании пользователя (это библиотека). «users» никогда не будет ToolImplX, но всегда IToolX (возможно, я должен был упомянуть, что конструкторы защищены, и у меня есть класс Factory, чтобы сделать что-то вроде: ITool1 * createTool1() {return new ToolImpl1();} –

+0

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

+0

: какие проблемы вы бы ожидать?Разве это не правда для всего кода, что может возникнуть проблема, если кто-то разрывает его appart, потому что сопровождающий не понимает оригинальный дизайн? IMHO - это то, что явные комментарии к коду ... –

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