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

相關問題