1. 程式人生 > >多繼承時基類命名衝突的解決方案

多繼承時基類命名衝突的解決方案

 眾所周知,C++與其他語言(如C#,JAVA)一個很大的不同就是C++支援從多個類繼承。
但是多繼承經常遇到這樣一種情況,如果有兩個或多個基類有相同名字和標記的方法,
繼承類該怎麼去實現。如有2個基類,程式碼如下:

小弟我研究了一下MFC和ATL中COM實現的部分,發現它們都很好地解決了這一問題,難能可貴的是

它們的解決方式都不一樣。下面我簡單地介紹一下。由於MFC和ATL原始碼都比較龐大,而且充斥著很多巨集,

在螢幕中列出來勢必會影響篇幅,小弟不才,仿照它們的風格簡單地寫個示例。

先看MFC風格的實現:

MFC採取巢狀類的方式來模擬出現這種問題的多繼承,有點麻煩而且不直觀,但卻是很有一般性。先上程式碼:

 

從程式碼可以看出,CDeriveMFCStyle嵌套了兩個類XBaseA和XBaseB,它們分別繼承自CBaseA和CBaseB,

並且CDeriveMFCStyle聲明瞭例項m_xBaseA和m_xBaseB做為成員變數。在XBaseA的Init實現中有這樣的一行程式碼:

這段程式碼很精妙,看了好幾遍我才看懂,原來在巢狀類中獲取外覆類的例項可以這樣做啊。以前我只會在巢狀類裡儲存

外覆類的指標,確實落了下乘。獲得外覆類的指標後,直接呼叫外覆類的成員方法BaseAInit,BaseAInit方法是專門為CBaseA的Init方法實現的。對於每個基類都可以以此類推。

由於是模擬多繼承,而不是真的繼承,因此要想將CDeriveMFCStyle 例項動態地轉換成父類指標,必須提供一個成員方法進行轉換,在這裡我使用了模板方法CastTo,內部就是一個簡單的分支語句來實現的。

使用示例:

看看效果,基本上模擬了多繼承,而且很好地解決了基類命名的衝突。

下面介紹一下ATL風格的解決方案:

照慣例先上程式碼:

這種實現真用了繼承,而沒有模擬。不過在繼承中增加了一箇中間層,CAdaptBaseA和CAdaptBaseB,這兩個類是模板類,分別繼承自CBaseA和CBaseB,模板引數是即將從它們派生的子類。這種模板是典型的ATL風格的模板,十分精妙。中間適配類CAdaptBaseA的Init實現中有一行程式碼:

這段程式碼,我初學ATL的時候也是看了好多遍才看懂,不過既然看懂了也就愛上這種風格了,同MFC風格的實現一樣,獲得子類例項pThis後,就直接呼叫子類中針對CBaseA::Init的實現BaseAInit成員方法了。

使用示例:

好了,兩種實現都介紹完畢了,歡迎諸位大俠提出批評。

參考資料:

《MFC Window程式設計》

《深入解析ATL(第2版)》