什麼是 COM 接口?

如果你瞭解 C# 或者 Java 語言,接口就會是一個非常熟悉的概念。接口是一個對象上一組操作的集合,不涉及任何實現的細節,接口標誌著方法和實現的分離。計算機中這種現象叫做解耦(decoupled)。

什麼是 COM 接口?

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

<code>// The following is not actual COM.

// Pseudo-C++:

interface IDrawable
{
void Draw();
};/<code>

這個例子來源於一些用來繪圖的庫中的對象。IDrawable 接口定義了繪圖中常用的操作,任何支持繪圖功能的對象都必須支持該接口。(慣例,接口名稱的首字母為 “I”),IDrawable 接口目前只定義了一個操作:Draw。

所有的接口都是抽象的,代碼中不能直接創建一個 IDrawable 接口的實例對象( C++ 語法規則不支持純虛函數對象的創建)。例如,下面的代碼是無法編譯通過的:

<code>IDrawable draw;
draw.Draw();/<code>

相反的,圖形庫都會提供一些對象來實現 IDrawable 所定義的接口。例如,可以實現一個叫做 Shape 的類或者一個叫做 Bitmap 的類,C++ 中使用繼承實現這種關係:

<code>class Shape : public IDrawable 

{
public:
virtual void Draw(); // Override Draw and provide implementation.
};

class Bitmap : public IDrawable
{
public:
virtual void Draw(); // Override Draw and provide implementation.
};/<code>

Shape 和 Bitmap 類定義了兩種不同的對象,二者都支持繪圖功能。每個類都繼承自 IDrawable 接口,而對於 Draw 方法繪製的具體實現細節可以各自不同。

如果程序中使用二者進行繪製,可以使用 IDrawable 的指針對象來操縱它們,而不是直接使用 Shape 和 Bitmap 對象的指針。

<code>IDrawable *pDrawable = CreateTriangleShape();

if (pDrawable)
{
pDrawable->Draw();
}/<code>

這有一個循環遍歷 IDrawable 接口指針的列子,在這個數組中,每項成員可能是 Shape 對象,也可能是 Bitmap 對象,更可能是一些支持 IDrawable 接口的其他對象,代碼中無需這些不同類型的實現細節,只需要調用它們都支持的共有接口 IDrawable 就可以繪製我們想要的圖像。

<code>void DrawSomeShapes(IDrawable **drawableArray, size_t count)
{
for (size_t i = 0; i < count; i++)
{
drawableArray[i]->Draw();
}
}/<code>

COM 組件 的一個關鍵點就是調用者永遠不需要知道派生類的具體實現細節。換句話說,在你的代碼中一般不會聲明 Shape 或者 Bitmap 類型的變量。所有的操作都是通過它們共有的接口 IDrawable 來完成。用這種方式,COM 組件可以做到接口和實現的完全分離。

你可以隨時改變 Shape 或者 Bitmap 對象的繪製方法,例如修復一個 bug,或者增加一些新的能力,對於調用者來說是透明的,調用者的代碼是無需任何修改的。

在 C++ 中,接口使用類或者結構體來實現。

文章中的代碼案例只是用來演示說明問題,真正的 COM 接口 定義顯然不會這樣簡單。一般一個 COM 接口的定義使用一種叫做 Interface Definition Language(IDL)—— 接口定義語言的東西。這個 IDL 文件將描述具體的接口行為,然後用 IDL 文件編譯器處理,生成一組 C++ 頭文件。

<code>class IDrawable
{
public:
virtual void Draw() = 0;
};/<code>

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

<code>// An interface for serialization.
class ISerializable
{
public:
virtual void Load(PCWSTR filename) = 0; // Load from file.
virtual void Save(PCWSTR filename) = 0; // Save to file.
};

// Declarations of drawable object types.

class Shape : public IDrawable
{
...
};

class Bitmap : public IDrawable, public ISerializable
{
...
};/<code>

在例子中,Bitmap 類實現了 ISerializable 接口,程序可以使用該接口保存和加載 Bitmap 對象。然而 Shape 類沒有實現這個接口,所以它不支持這個功能。下面是例子中的繼承關係:

什麼是 COM 接口?

上面的文字只是簡單的介紹 COM 組件 的一些概念,目前我們還沒有看見過一個真正的 COM 組件,接下來的內容從每個 COM 應用都必須做的一件事開始 —— COM 庫初始化。


分享到:


相關文章: