2012-02-16 9 views
2

В C++ чистые виртуальные классы часто используются для полиморфизма времени выполнения.Можете ли вы использовать CRTP и функции с интерфейсом в качестве параметра?

Так у вас есть:

class IInterfaceA 
{ 
    virtual void DoFoo() = 0; 
}; 

и производные классы, как:

class CFancyObject : public IInterfaceA 
{ 
... 

, которые затем могут быть использованы в функции, как:

void Foo(IInterfaceA &interface); 

Но это во время выполнения дела, и если объекты известны во время компиляции, мы можем сделать это лучше, используя CRTP:

template<class T> class IInterfaceA 
{ 
public: 
    void DoFoo() 
    {  
     static_cast<T*>(this)->CallDerivedFunction(); 
    } 
} 

class CFancyObject : public IInterfaceA<CFancyObject> 
{ 
    ... 
} 

Возможно ли использовать производные классы на основе CRTP в функциях, которые принимают IInterface в качестве параметра?

void Foo(IInterfaceA<?> &interface); 
+0

Не можете ли вы иметь не-шаблонный базовый интерфейс, из которого наследуется шаблонный интерфейс? – Nick

+0

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

ответ

2

Интерфейс предназначен для того, чтобы отделить API класса от его реализации. Введя параметр шаблона, вы тесно связываете реализацию с интерфейсом, победив всю цель. CRTP предназначен для решения различных задач.

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

template<class T> 
void Foo(IInterfaceA<T> &interface) { interface.DoFoo(); } 

идентичен и не дает никаких преимуществ по сравнению с

template<class T> 
void Foo(T &object) { object.DoFoo(); } 
+0

Разница в соединении - это только время выполнения и время компиляции. Шаблонный базовый класс по-прежнему отделяет интерфейс от реализации, все равно потребуется меньше времени для перехода на полностью новую реализацию производного класса. И все производные классы, которые получены из базы, на самом деле практически взаимозаменяемы. Я думаю, что даже 'template void Foo (IInterfaceA & interface);' будет работать, но он все еще очень неуклюжий и intellisense враждебный, поэтому я задаюсь вопросом, есть ли опрятный способ решить проблему. – Coder

+0

@Coder, точка, которую я пыталась сделать, заключается в том, что * пользователю * интерфейса требуется полное определение конкретного класса, чтобы заполнить параметр шаблона. В этот момент нет никакой пользы для класса интерфейса, вы можете напрямую работать с конкретным классом. –

+0

Пособие, которое я вижу, является СУХОЙ. Если 3 или 4 класса имеют один и тот же интерфейс, но разные реализации, я могу использовать одну функцию для их обработки. В то же время избегайте чрезмерных затрат времени на запуск чистых виртуальных классов и предлагайте диагностику ошибок времени компиляции. Но с DerivedA, DerivedB, DerivedC, все из которых основаны на CRTPBaseA, я просто не вижу способа использовать один единственный приемник для всех из них. – Coder

0

не могли бы вы просто сделать:

template<class T> class IInterfaceA 
{ 
public: 
    template<class T2> 
    void DoFoo(IInterfaceA<T2> &interface) 
    {  
     static_cast<T*>(this)->CallDerivedFunction(interface); 
    } 
} 

class CFancyObject : public IInterfaceA<CFancyObject> 
{ 
    template<class T2> 
    CallDerivedFunction(IInterfaceA<T2> &interface) {...} 
} 

?