2012-02-16 72 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> 
{ 
    ... 
} 

在使用IInterface作为参数的函数中,是否可以使用基于CRTP的派生类?

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

难道你不能只有一个非模板化的基础接口,模板化接口从中继承吗? – Nick 2012-02-16 17:03:01

+0

@Nick:但它必须调用派生类的成员函数,它必须在编译时计算。我不太清楚如何在代码中描述。 – Coder 2012-02-16 17:05:35

回答

2

接口意味着将类的API从其实现中分离出来。通过引入模板参数,您可以将实现与接口紧密结合,从而达到整个目的。 CRTP是为了解决一组不同的问题。

如果将界面模板化,则将其作为参数的函数也必须进行模板化。一旦你完成了,使用接口类和使用实现类没有区别。

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

是相同的,并在

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

耦合的区别仅在于运行时间与编译时间。模板化的基类仍将接口从实现中分离出来,它仍然需要更少的时间来切换到全新的派生类实现。而从Base派生的所有派生类实际上几乎可以互换。我猜即使是'template void Foo(IInterfaceA &interface);'可以工作,但它仍然非常笨拙和intellisense敌意,所以我想知道是否有一个简洁的方法来解决问题。 – Coder 2012-02-16 17:28:28

+0

@Coder,我试图做的一点是,接口的*用户*需要具体类的完整定义才能填充模板参数。那时,接口类没有任何好处,你可以直接使用具体类。 – 2012-02-16 17:36:01

+0

我看到的好处是DRY。如果3或4类具有相同的接口,但实现不同,我可以使用一个函数来处理它们。同时避免纯虚拟类的运行时间开销并提供编译时错误诊断。但与DerivedA,DerivedB,DerivedC所有这些都基于CRTPBaseA我只是没有办法如何使用一个单一的接收器为他们所有。 – Coder 2012-02-16 17:43:48

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

相关问题