Inside COM讀書筆記------接口

1.接口的作用


組件可以充應用程序中刪除並可用另外一個組件代替,只要新的組件支持同樣的接口。單個組件並不能起決定性作用,相反,用以連接組件的接口對應用程序親戚到決定性作用。使用組件來構成應用程序最大優點在於可以複用應用程序的結構。
接口可以保護系統免受外界變化的影響、接口可以使得客戶用相同的方式處理不同的組件。

2.COM接口的實現


class IX                   //First Interface
{
public:
       virtual void Fx1() = 0;
       virtual void Fx2() = 0;
};

class IY                 //Second Interface
{
public:
       virtual void Fy1() = 0;
       virtual void Fy2() = 0;
};

class CA : public IX, public IY
{
public:
       //implement Interface IX
       virtual void Fx1(){cout<<"Fx1()"<<endl;}
       virtual void Fx2(){cout<<"Fx2()"<<endl;}
       //implement Interface IY
       virtual void Fy1(){cout<<"Fy1()"<<endl;}
       virtual void Fy2(){cout<<"Fy2()"<<endl;}
};

IX和IY是用於實現接口的純抽象基類。組件CA繼承了IX和IY接口。抽象基類指定了起派生類應提供哪些函數。而派生類則具體實現這些函數,對純虛類的繼承稱作接口繼承。com接口必須繼承至IUnknown接口。
在objbase.h中定義:#define interface struct    所以使用struc 就不必留有public更簡潔。

總結:
  • com接口在c++中是用純抽象基類實現的
  • 一個com組件可以提供多個接口
  • 一個c++類可以使用多繼承來實現一個了可以提供多個接口的組件
      (1) __stdcall調用  
          __stdcall是Pascal程序的缺省調用方式,參數採用從右到左的壓棧方式,被調函數自身在返回前清空堆棧。WIN32 Api都採用__stdcall調用方式,這樣的宏定義說明了問題: #define WINAPI _stdcall  按C編譯方式,__stdcall調用約定在輸出函數名前面加下劃線,後面加“@”符號和參數的字節數,形如_functionName@nnn。

      (2) __cdecl調用 
          __cdecl是C/C++的缺省調用方式,參數採用從右到左的壓棧方式,傳送參數的內存棧由調用者維護。__cedcl約定的函數只能被C/C++調用,每一個調用它的函數都包含清空堆棧的代碼,所以產生的可執行文件大小會比調用__stdcall函數的大。 由於_cdecl調用方式的參數內存棧由調用者維護,所以變長參數的函數能(也只能)使用這種調用約定。由於Visual C++默認採用__cdecl 調用方式,所以VC中中調用DLL時,用戶應使用__stdcall調用約定。按C編譯方式,__cdecl調用約定僅在輸出函數名前面加下劃線,形如_functionName。

3.實現細節

  • 類並非組件
  • 接口並非總是繼承的
     可以用一個類實現幾個不同的接口,還可以用單個的類來實現每一個接口
  • 多重接口及多重繼承
     一個接口是一個函數集合、一個組件是一個接口集合,而一個系統是一系列組件的集合。
  • 命名衝突

4.接口的背後


虛擬函數表
     當定義一個抽象基類時,定義的實際上是一個內存塊的結構。純抽象基類所有實現都是一些具有相同的基本結構的內存塊
interface IX
{
       virtual void __stdcall Fx1() = 0;
       virtual void __stdcall Fx2() = 0;
       virtual void __stdcall Fx3() = 0;
       virtual void __stdcall Fx4() = 0;
};
定義一個純抽象基類也就是定義了相應的內存結構。次內存在派生類中實現此抽象基類的時候纔會分配。當派生類繼承一個抽象基類時,將繼承此內存結構:
一個抽象基類定義的內存結構分爲兩部分。上圖右邊是虛擬函數表(vtbl)其中包含一組指向虛擬函數實現的指針,vtbl中第一項爲派生類中所實現Fx1函數的地址。左側爲一個指向vtbl的指針,指向抽象基類的指針則指向vtbl指針。

vtbl指針及實例數據
class CA: public IX
{
public:
       //implement interface IX
       virtual void __stdcall Fx1(){cout<< "CA::Fx1()"<<endl;}
       virtual void __stdcall Fx2(){cout<<m_Fx2<<endl;}
       virtual void __stdcall Fx3(){cout<<m_Fx3<<endl;}
       virtual void __stdcall Fx4(){cout<<m_Fx4<<endl;}
       //
      CA( double d):m_Fx2(d*d),m_Fx3(d*d*d),m_Fx4(d*d*d*d){}
       //interface data
       double m_Fx2;
       double m_Fx3;
       double m_Fx4;
};




發佈了154 篇原創文章 · 獲贊 870 · 訪問量 85萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章