2016-06-14 3 views
1

У меня есть интерфейс и класс, реализующий его:Как сказать C++ подмешать интерфейс он реализует

class InterfaceA 
{ 
public: 
    enum Enum { X, Y, Z }; 
    virtual void foo(Enum &) = 0; 
    virtual void bar() = 0; 
}; 

class ClassA : public InterfaceA 
{ 
public: 
    virtual void foo(Enum & a) { 
     a = X; 
    } 
    virtual void bar(); 
}; 

Мне нужно расширить функциональность реализующего класса InterfaceA в одном аспекте. По моему мнению, для этого нужны миксины.

E.g. foo() должен изменить значение параметра в каком-либо состоянии. Вот как я это делаю:

template <typename T> 
class Mixin : public T 
{ 
public: 
    virtual void foo(Enum & a) { 
     T::foo(a); 
     if (a == X){ 
      a = Y; 
     } 
    } 
}; 

Проблема заключается в том, что не будет компилироваться, если я или не писать области действия префиксов идентификаторы, определенные в классе интерфейса или определение типа во их следующим образом:

template <typename T> 
class Mixin : public T 
{ 
public: 
    typedef InterfaceA::Enum Enum; 
    virtual void foo(Enum & a) { 
     T::foo(a); 
     if (a == InterfaceA::X){ 
      a = InterfaceA::Y; 
     } 
    } 
}; 

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

ответ

0

Enum, X и Y должны зависеть имяТипа.

И вы можете использовать static_assert для принудительного наследования.

template <typename T> 
class Mixin : public T 
{ 
public: 
    static_assert(std::is_base_of<InterfaceA, T>::value, 
        "T should inherit from InterfaceA"); 

    virtual void foo(typename T::Enum & a) { 
     T::foo(a); 
     if (a == T::X){ 
      a = T::Y; 
     } 
    } 
}; 
+0

static_assert классный, но что бы вы предложили в среде pre-C++ 11? – peti

+0

@peti: вы можете посмотреть на [how-to-do-static-assert-with-macros] (http://stackoverflow.com/questions/14621968/how-to-do-static-assert-with-macros) – Jarod42

0

Я полагаю, вы должны использовать виртуальное наследование; это должно избегать проблемы с «страшным алмазом».

Что-то вроде

class InterfaceA 
{ 
    public: 
     enum Enum { X, Y, Z }; 
     virtual void foo(Enum &) = 0; 
     virtual void bar() = 0; 
}; 

class ClassA : public virtual InterfaceA 
{ 
    public: 
     virtual void foo(Enum & a) { 
     a = X; 
     } 
     virtual void bar() { 
     } 
}; 

template <typename T> 
class Mixin : public T, public virtual InterfaceA 
{ 
    public: 
     virtual void foo(Enum & a) { 
     T::foo(a); 
     if (a == X){ 
      a = Y; 
     } 
     } 
}; 


int main() 
{ 
    Mixin<ClassA> m; 

    return 0; 
} 
Смежные вопросы