我們先來看一組接口定義:
struct IX { virtual void MethodX() = 0; }; struct IXA : public IX { virtual void MethodXA() = 0; }; struct IXB : public IX { virtual void MethodXB() = 0; }; struct IXAB : public IXA, public IXB { virtual void MethodXAB() = 0; }; |
然后我們來實現(xiàn) IX:
struct CX : public IX { virtual void MethodX() { } }; |
然后再來實現(xiàn) IXA:
struct CXA : public IXA { virtual void MethodX() { } virtual void MethodXA() { } }; |
這樣寫當然是沒問題的。但是,有木有發(fā)現(xiàn),這里出現(xiàn)MethodX了。如果,我們需要之前CX中對MethodX的實現(xiàn),那怎么辦呢?
一開始我傻傻地想,繼承CX不就好了么:
struct CXA : public IXA, public CX { virtual void MethodXA() { } }; |
結果實例化CXA的時候報錯:
error C2259: 'CXA' : cannot instantiate abstract class
due to following members:
void IX::MethodX(void)' : is abstract
see declaration of 'IX::MethodX'
(嘿嘿。我不知道是不是挺多人一開始都會這么想的。)究其原因,是因為添加多繼承不會產生覆蓋虛函數(shù)的效果。此時虛函數(shù)的狀態(tài)是:
MethodX | 來自于IXA | 來自于IX | 未實現(xiàn) |
MethodXA | 來自于IXA | | CXA實現(xiàn) |
MethodX | 來自于CX | 來自于IX | CX實現(xiàn) |
新添加的CX中的MethodX,只是覆蓋了CX多繼承的IX中的那個MethodX。退一步,即便CX是個獨立的類,沒有繼承于IX,CX中的MethoxX也無法為覆蓋IXA中的MethodX。只有處于同一繼承鏈中的各個類才會產生覆蓋虛函數(shù)的效果。
假如,CX就是繼承于IXA的,且只實現(xiàn)了MethodX,未實現(xiàn)MethodA:
struct CX : public IXA { virtual void MethodX() { } }; |
然后CXA不再繼承IXA,而是直接繼承CX,補充實現(xiàn)MethodA:
struct CXA : public CX { virtual void MethodXA() { } }; |
這樣,CXA是可以直接實例化的。但是,CX又無法單獨使用了!
CX面臨的問題是,需要隨時被改變基類,也就是基類類型可配置。于是我們想到了模版:
template <typename T = IX> struct CX : public T { virtual void MethodX() { } }; struct CXA : public CX<IXA> { virtual void MethodXA() { } }; |
CX單獨使用的時候,使用默認模版參數(shù),讓它繼承于IX;被CXA使用的時候,讓它繼承于IXA,問題就解決了!同樣的方法,我們實現(xiàn)CXB:
struct CXB : public CX<IXB> { virtual void MethodXB() { } }; |
下面我們來實現(xiàn)IXAB:
struct CXAB : public IXAB { virtual void MethodX() { } virtual void MethodXA() { } virtual void MethodXB() { } virtual void MethodXAB() { } }; |
注意到這里只有一個MethodX。由于MethodX對IXA、IXB是同源的,IXAB里面雖然本應該有兩個MethodX,但編譯器進行合并處理,對其中一個做跳轉,所以我們只需要實現(xiàn)一次就夠了。(目前我是這樣理解的。)不過這不是本文要探討的內容,我們關注的是,MethodX、MethodXA、MethodXB又要重復寫一遍了。
看來我們要對CXA、CXB也做模版處理:
template <typename T = IXA> struct CXA : public CX<T> { virtual void MethodXA() { } }; template <typename T = IXB> struct CXB : public CX<T> { virtual void MethodXB() { } }; struct CXAB : public CXA<IXAB>, public CXB<IXAB> { virtual void MethodXAB() { } }; |
可惜的是,還是有錯誤:
error C2259: 'CXAB' : cannot instantiate abstract class
due to following members:
'void IXB::MethodXB(void)' : is abstract
see declaration of 'IXB::MethodXB'
'void IXA::MethodXA(void)' : is abstract
see declaration of 'IXA::MethodXA'
說的是CXA<IXAB>中的MethodXB未實現(xiàn),CXB<IXAB>中的MethodXA未實現(xiàn)……所以,以上方案不適合接口中存在多繼承的情形。
恰好COM中貌似也沒有接口多繼承的情形。我們將CX改名為IXImpl,將CXA改名為IXAImpl,將CXB改名為IXBImpl:
struct IX { virtual void MethodX() = 0; }; struct IXA : public IX { virtual void MethodXA() = 0; }; struct IXB : public IX { virtual void MethodXB() = 0; }; template <typename T = IX> struct IXImpl : public T { virtual void MethodX() { } }; template <typename T = IXA> struct IXAImpl : public IXImpl<T> { virtual void MethodXA() { } }; template <typename T = IXB> struct IXBImpl : public IXImpl<T> { virtual void MethodXB() { } }; |
是不是跟ATL對上號了?這些*Impl類可以直接使用(如果是需要默認實現(xiàn)就夠了),也可以被繼承,被繼承的時候也可以更換基類。如:
struct CXA : public IXAImpl<> { }; |
struct IY : public IXB { virtual void MethodY() = 0; }; struct CY : public IXBImpl<IY> { virtual void MethodY() { } }; |
第二個例子中,IXB是庫提供的接口,IY是應用程序設計的接口,CY是應用程序實現(xiàn)的類。
好了,ATL中的*Impl類的做法就是如此,只是多了其他一些模版參數(shù),暫時不理它們。
posted on 2012-09-02 13:56
溪流 閱讀(2936)
評論(1) 編輯 收藏 引用 所屬分類:
C++ 、
Windows 、
COM