如果你了解C#或者Java語言,接口就會(huì)是一個(gè)非常熟悉的概念。接口是一個(gè)對象上一組操作的集合,不涉及任何實(shí)現(xiàn)的細(xì)節(jié),接口標(biāo)志著方法和實(shí)現(xiàn)的分離。計(jì)算機(jī)中這種現(xiàn)象叫做解耦(decoupled)。

在C++中,最接近于接口概念的就是純虛類(purevirtualclass)。純虛類就是一個(gè)僅僅包含純虛函數(shù)的類,除了純虛函數(shù)不含有任何其它的成員變量或者函數(shù),如:

這個(gè)例子來源于一些用來繪圖的庫中的對象。IDrawable接口定義了繪圖中常用的操作,任何支持繪圖功能的對象都必須支持該接口。(慣例,接口名稱的首字母為“I”),IDrawable接口目前只定義了一個(gè)操作:Draw。
所有的接口都是抽象的,代碼中不能直接創(chuàng)建一個(gè)IDrawable接口的實(shí)例對象(C++語法規(guī)則不支持純虛函數(shù)對象的創(chuàng)建)。例如,下面的代碼是無法編譯通過的:

相反的,圖形庫都會(huì)提供一些對象來實(shí)現(xiàn)IDrawable所定義的接口。例如,可以實(shí)現(xiàn)一個(gè)叫做Shape的類或者一個(gè)叫做Bitmap的類,C++中使用繼承實(shí)現(xiàn)這種關(guān)系:

Shape和Bitmap類定義了兩種不同的對象,二者都支持繪圖功能。每個(gè)類都繼承自IDrawable接口,而對于Draw方法繪制的具體實(shí)現(xiàn)細(xì)節(jié)可以各自不同。
如果程序中使用二者進(jìn)行繪制,可以使用IDrawable的指針對象來操縱它們,而不是直接使用Shape和Bitmap對象的指針。

這有一個(gè)循環(huán)遍歷IDrawable接口指針的列子,在這個(gè)數(shù)組中,每項(xiàng)成員可能是Shape對象,也可能是Bitmap對象,更可能是一些支持IDrawable接口的其他對象,代碼中無需這些不同類型的實(shí)現(xiàn)細(xì)節(jié),只需要調(diào)用它們都支持的共有接口IDrawable就可以繪制我們想要的圖像。

COM組件的一個(gè)關(guān)鍵點(diǎn)就是調(diào)用者永遠(yuǎn)不需要知道派生類的具體實(shí)現(xiàn)細(xì)節(jié)。換句話說,在你的代碼中一般不會(huì)聲明Shape或者Bitmap類型的變量。所有的操作都是通過它們共有的接口IDrawable來完成。用這種方式,COM組件可以做到接口和實(shí)現(xiàn)的完全分離。
你可以隨時(shí)改變Shape或者Bitmap對象的繪制方法,例如修復(fù)一個(gè)bug,或者增加一些新的能力,對于調(diào)用者來說是透明的,調(diào)用者的代碼是無需任何修改的。
在C++中,接口使用類或者結(jié)構(gòu)體來實(shí)現(xiàn)。
文章中的代碼案例只是用來演示說明問題,真正的COM接口定義顯然不會(huì)這樣簡單。一般一個(gè)COM接口的定義使用一種叫做InterfaceDefinitionLanguage(IDL)——接口定義語言的東西。這個(gè)IDL文件將描述具體的接口行為,然后用IDL文件編譯器處理,生成一組C++頭文件。

當(dāng)你在使用COM組件的時(shí)候,一定要記住接口不是對象。它們是一組必須實(shí)現(xiàn)的方法集合。一些對象可以實(shí)現(xiàn)一樣的接口,例如代碼中的Shape對象和Bitmap對象。另外一個(gè)對象可以實(shí)現(xiàn)幾個(gè)接口,例如,一個(gè)圖形庫可能定義一個(gè)名字叫做ISerializable的接口對象,它用來保存和加載圖形對象數(shù)據(jù)(圖形的序列化)。現(xiàn)在考慮下面的代碼:

在例子中,Bitmap類實(shí)現(xiàn)了ISerializable接口,程序可以使用該接口保存和加載Bitmap對象。然而Shape類沒有實(shí)現(xiàn)這個(gè)接口,所以它不支持這個(gè)功能。下面是例子中的繼承關(guān)系:

上面的文字只是簡單的介紹COM組件的一些概念,目前我們還沒有看見過一個(gè)真正的COM組件,接下來的內(nèi)容從每個(gè)COM應(yīng)用都必須做的一件事開始——COM庫初始化。
責(zé)任編輯人:CC
電子發(fā)燒友App


























評論