激情欧美日韩一区二区,浪货撅高贱屁股求主人调教视频,精品无码成人片一区二区98,国产高清av在线播放,色翁荡息又大又硬又粗视频

C++類(lèi)的動(dòng)態(tài)組件化技術(shù)

時(shí)間:2024-10-12 04:18:33 計算機應用畢業(yè)論文 我要投稿
  • 相關(guān)推薦

C++類(lèi)的動(dòng)態(tài)組件化技術(shù)

  論文關(guān)鍵詞:COM組件 接口 生命周期 C++類(lèi) ATL組件類(lèi) C++基類(lèi) ATL模板基類(lèi) 繼承

  論文摘要:在組件化編程的時(shí)代,如何復用累積的大量沒(méi)有組件特性的C++類(lèi)?本文從工程的角度對這一問(wèn)題進(jìn)行探討,利用現有組件技術(shù),提出了一套將C++類(lèi)平滑過(guò)渡到COM組件的完整解決方案。

  1. 問(wèn)題的提出

  自從Microsoft公布了COM(Component Object Model,組件對象模型,簡(jiǎn)稱(chēng)COM)技術(shù)以后,Windows平臺上的開(kāi)發(fā)模式發(fā)生了巨大的變化,以COM為基礎的一系列組件技術(shù)將Windows編程帶入了組件化時(shí)代,傳統的面向對象的軟件開(kāi)發(fā)方法已經(jīng)逐漸被面向組件的方法所取代。

  COM標準建立在二進(jìn)制可執行代碼級的基礎上,不論何種工具、開(kāi)發(fā)的組件,只要符合COM規范,就可復用于VC、VB、Delphi、BC等各種開(kāi)發(fā)中。COM的語(yǔ)言無(wú)關(guān)性將軟件復用的層次從源代碼級推進(jìn)到了二進(jìn)制級,復用更方便,也更安全。

  然而,COM技術(shù)帶來(lái)全新的軟件設計和開(kāi)發(fā)模式的同時(shí),也帶來(lái)了新的問(wèn)題。

  許多軟件公司在開(kāi)發(fā)自己的軟件產(chǎn)品過(guò)程中,都累積了大量C++類(lèi),這些代碼設計精良,功能完備,以面向對象的標準來(lái)無(wú)可挑剔。然而,這些代碼不支持COM,將無(wú)法在COM時(shí)代繼續被復用。如果它們在軟件組件化的趨勢中被淘汰,那對軟件公司和開(kāi)發(fā)人員來(lái)說(shuō)都是極大的損失。

  COM專(zhuān)家Don Box曾說(shuō)過(guò),“COM is a super C++”。這給了我們一個(gè)啟示,是否可以實(shí)現一種技術(shù),能夠動(dòng)態(tài)的為普通C++類(lèi)加上一層COM的封裝呢?這樣,既可以保持這些代碼自身的完整和特性,使它們能繼續應用于原來(lái)的系統,也可以在需要作為組件使用的時(shí)候,把它們動(dòng)態(tài)轉變成組件,復用于新系統。

  一個(gè)自然而然的想法是,為每一個(gè)C++類(lèi)開(kāi)發(fā)一個(gè)只暴露一個(gè)接口的COM組件,將原C++類(lèi)的每個(gè)public方法都對應于該接口的一個(gè)方法,接口方法的實(shí)現可以簡(jiǎn)單的調用相對應的C++類(lèi)方法即可。這樣,程序由原有的C++類(lèi)控制,但COM層的封裝則由組件提供;舅悸啡缦聢D所示:

  

  本文就這一技術(shù)展開(kāi)討論,最終提供一套由普通C++類(lèi)平滑過(guò)渡到COM組件的完整解決方案。我們選用ATL(Active Template Library,活動(dòng)模板庫,簡(jiǎn)稱(chēng)ATL)作為COM組件的開(kāi)發(fā)工具,開(kāi)發(fā)環(huán)境為Visual Studio 6.0。如沒(méi)有特殊說(shuō)明,下文中的“C++類(lèi)”指沒(méi)有組件特性C++類(lèi),“C++對象”指C++類(lèi)的實(shí)例;“ATL組件類(lèi)”指用于包裝的ATL類(lèi),“ATL對象”指ATL組件類(lèi)的實(shí)例。

  2. 用ATL包裝C++類(lèi)

  按上述思路將C++對象動(dòng)態(tài)組件化后,所得的組件實(shí)際上由兩部分組成:ATL組件對象和綁定的C++對象。兩者的生命周期互相牽制,但要保持一致。生命周期的是C++類(lèi)動(dòng)態(tài)組件化的首要難點(diǎn)。

  C++類(lèi)分為兩種,一種是簡(jiǎn)單的C++類(lèi),一種是集合型的C++類(lèi)。集合型的C++對象管理一組C++對象,負責其創(chuàng )建和刪除,維護它們的生命周期。下面,分別就簡(jiǎn)單C++類(lèi)和集合型C++類(lèi)的組件化技術(shù)進(jìn)行說(shuō)明,展示解決方案的核心技術(shù)。

  2.1. 簡(jiǎn)單C++類(lèi)的組件化

  為使ATL組件類(lèi)可以自由調用C++類(lèi)的方法,需要:

  l 為ATL組件類(lèi)安插一個(gè)指針成員變量,指向C++類(lèi)

  l 提供ATL對象和C++對象的綁定機制

  我們可以在A(yíng)TL組件類(lèi)初始化時(shí)創(chuàng )建一個(gè)C++類(lèi),用成員變量m_pCPPObj記錄,在析構時(shí)刪除,從而實(shí)現ATL組件類(lèi)和C++類(lèi)的天然綁定。但出于靈活性考慮,使得ATL組件對象可以綁定任意C++類(lèi)的對象,我們?yōu)锳TL組件類(lèi)添加一個(gè)綁定函數Link2CPPObj(CImplement* pObj)。

  在A(yíng)TL組件類(lèi)的構造函數內,創(chuàng )建一個(gè)C++對象,用m_pCPPObj記錄。

  如果調用了Link2CPPObj,則將m_pCPPObj指向的對象刪除,改用傳入的C++對象。

  在A(yíng)TL組件類(lèi)的的析構函數內,刪除其綁定的C++對象。由構造函數和Link2CPPObj函數的定義可知,m_pCPPObj指針總是有意義的。

  簡(jiǎn)單C++類(lèi)組件化的思想如下圖所示:

  

  2.2. 集合型C++類(lèi)的組件化

  集合型C++類(lèi)的情況有所不同。

  集合型C++類(lèi)以數組(array)、列表(list)、映射表(map)的形式其它C++對象。集合對象和它管理的元素對象都被包裝成組件后,集合型ATL對象可能調用一個(gè)“Destroy”方法,期望刪除某一個(gè)元素ATL對象;這一操作的實(shí)質(zhì)卻是,集合型C++對象的“Destroy”方法被調用,將元素C++對象刪除了,而元素ATL對象卻不知道。這一操作的結果導致了元素的ATL對象存在,而其綁定的C++對象卻被刪除的情況,兩者的生命周期出現了不一致。

  為了解決這個(gè)問(wèn)題,我們需要在C++對象被刪除時(shí),能將ATL對象同時(shí)刪除;而在A(yíng)TL對象的引用計數為0需要刪除自身時(shí),也能把C++對象刪除?尚械慕鉀Q方案是:

  l 在C++類(lèi)中保存一個(gè)接口指針,指向綁定在一起的ATL對象;為該接口指針賦值的最佳地點(diǎn)顯然是提供綁定機制的Link2CPPObj函數內部,為此,還需要給Link2CPPObj添加一個(gè)IUnknown*參數

  l 在C++類(lèi)的析構函數中,判斷該接口指針是否為空,如果不為空,則Release對接口的引用,引發(fā)ATL對象自身的析構

  現在,技術(shù)方案如下圖所示:

  

  2.3. 內部創(chuàng )建的組件和外部創(chuàng )建的組件

  集合型C++類(lèi)組件化后仍然是集合型ATL組件,它可以創(chuàng )建、刪除自己管理的組件。這樣,組件的創(chuàng )建就可能有兩種情況:

  l 由客戶(hù)直接創(chuàng )建

  l 由客戶(hù)調用集合型組件的接口方法間接創(chuàng )建

  創(chuàng )建方式的不同導致了組件生命周期的復雜性。一般說(shuō)來(lái),組件的創(chuàng )建者負責維護組件的生命周期。上述兩種情況下,分別由客戶(hù)和集合型組件維護被創(chuàng )建組件的生命周期。然而,另有一種情況是,客戶(hù)創(chuàng )建了一個(gè)組件,然后送交一個(gè)集合型組件管理,現在維護組件生命周期的責任就由客戶(hù)轉交給了集合型組件。

  我們的解決方案必須提供這樣的健壯性和靈活性,以維護各種情況下組件的生命周期。我們?yōu)锳TL組件類(lèi)添加一個(gè)BOO成員m_bInnerManage,作為組件的維護標識。內部維護意味著(zhù)組件的生命周期由其它組件(集合型組件)維護;外部維護則是由客戶(hù)維護。

  

  缺省情況下,組件是外部創(chuàng )建并維護的,在組件的構造函數內設置外部維護標識。集合型組件創(chuàng )建元素時(shí),需要為元素分別創(chuàng )建一個(gè)C++對象和一個(gè)ATL對象,然后調用ATL對象的Link2CPPObj函數將兩者綁定在一起,在Link2CPPObj函數內修改維護標識。對于第三種情況,可以在外部創(chuàng )建組件由客戶(hù)轉交給集合型組件時(shí),在集合型組件相應方法內重新設置維護標識。

  2.4. C++基類(lèi)

  為了對現有C++類(lèi)的改動(dòng)最小,我們設計一個(gè)基類(lèi)封裝需要為C++類(lèi)添加的功能。所有需要動(dòng)態(tài)組件化的C++類(lèi)都必須從這個(gè)基類(lèi)派生,以保證動(dòng)態(tài)組件化中C++對象與ATL對象生命周期的一致。如下圖示:

  

  實(shí)現代碼如下所示:

class CCPP2ATLObjBase

{

       CCPP2ATLObjBase ();

public:

       // IUnknown指針,反指向封裝該CPP類(lèi)的接口

       IUnknown*    m_pAssociATLUnk;

protected:

       virtual ~ CCPP2ATLObjBase ();

};

CCPP2ATLObjBase::CCPP2ATLObjBase()

{

       // 將IUnknown指針初始化為0

       m_pAssociATLUnk = NULL;

}

CCPP2ATLObjBase::~CCPP2ATLObjBase()

{

       // CPP類(lèi)的對象析構時(shí),Release對接口的引用

       if (m_pAssociATLUnk)

              m_pAssociATLUnk->Release();

}

然后,修改現有各個(gè)C++類(lèi),使之從CCPP2ATLObjBase派生,如下面代碼片斷所示:

class CImplement : public CCPP2ATLObjBase

{

       ……

};

  必須指出的是,在CCPP2ATLObjBase基類(lèi)中,我們設置的m_pAssociATLUnk變量存在和現有C++類(lèi)成員命名沖突的問(wèn)題。但是,考慮到原C++類(lèi)并沒(méi)有組件特性,也應該不會(huì )有“IUnknown”型指針,因此,只要各個(gè)類(lèi)的變量命名都按照規范的命名法,出現這種名字沖突的可能性是極小的。

  2.5. ATL模板基類(lèi)

  通過(guò)以上分析,我們發(fā)現,所有的ATL組件類(lèi)都需要實(shí)現一些相同的功能:

  l 保留一個(gè)指向其綁定C++對象的指針

  l 提供一個(gè)Link2CPPObj函數

  l 在構造函數中創(chuàng )建一個(gè)綁定C++類(lèi)的對象

  為了減化編碼,我們定義一個(gè)帶參數的模板基類(lèi),實(shí)現上述功能,模板參數就是綁定的C++類(lèi)。然后,所有的ATL組件類(lèi)都從模板基類(lèi)中派生,F在的技術(shù)方案如下圖所示:

  

實(shí)現代碼如下所示:

template <class T>

class CCPP2ATLTemplateBase :

{

protected:

       // C++類(lèi)指針

       T*          m_pCPPObj;

       // 標識繼承該模板的ATL對象是否由內部維護

       BOOL     m_bInnerManage;

public:

       /**********************************************************

         模板的構造函數,實(shí)現如下功能:

         1、new一個(gè)C++實(shí)現類(lèi)對象

         2、缺省情況下,ATL對象由外部維護,將內部維護標識設為FALSE

         3、將C++類(lèi)中對ATL接口的反指指針設置為空

       **********************************************************/

       CAtlCPP2ATLTemplateBase()

       {

              m_pCPPObj = new T;

              m_bInnerManage = FALSE;

              m_pCPPObj->m_pAssociATLUnk = NULL;

       }

       /**********************************************************

         析構ATL對象時(shí),如果該ATL對象是由外部創(chuàng )建的,

         則顯式的刪除C++對象

         如果ATL對象由內部維護,那么什么事都不用做

       **********************************************************/

       virtual ~CAtlCPP2ATLTemplateBase()

       {

              if (!m_bInnerManage) {

                     if (m_pCPPObj)

                            delete m_pCPPObj;

              }

       }

       /**********************************************************

         Link2CPPObj函數,負責綁定C++對象和ATL接口

         1、刪除構造函數中new的C++對象,而使用外部傳入的C++對象

         2、將ATL對象的內部維護標識設為T(mén)RUE

         3、設置C++基類(lèi)中的接口指針成員

         4、因為ATL接口傳送給外部使用,需要增加引用計數

       **********************************************************/

       virtual void Link2CPPObj(T* pObj, IUnknown* pUnk)

       {

              ASSERT(pObj != NULL);

              ASSERT(pUnk != NULL);

              if (m_pCPPObj)

                     delete m_pCPPObj;

              m_pCPPObj = pObj;

              m_bInnerManage = TRUE;

              m_pCPPObj->m_pAssociATLUnk = pUnk;

              m_pCPPObj->m_pAssociATLUnk->AddRef();

       }

};

然后,每個(gè)ATL類(lèi)都從該模板類(lèi)派生,如下代碼片斷所示:

class ATL_NO_VTABLE CATLXX :

       ……,

       // 添加ATL模板基類(lèi)

       public CCPP2ATLTemplateBase<CImplementXX>

{

       ……

}

  3.   C++參數類(lèi)型的自動(dòng)化包裝

  在本文的技術(shù)方案中,C++類(lèi)的public方法與ATL組件接口中的方法一一對應;相應的,C++類(lèi)中方法的參數類(lèi)型也要轉換為COM規范所允許的數據類(lèi)型。

  在基于COM的自動(dòng)化(Automation)技術(shù)中,Microsoft提供了一套自動(dòng)化兼容的數據類(lèi)型VARIANT,定義如下:

  typedef struct FARSTRUCT tagVARIANT VARIANT;

  typedef struct FARSTRUCT tagVARIANT VARIANTARG;

  typedef struct tagVARIANT {

       VARTYPE                        vt;

       unsigned short                  wReserved1;

       unsigned short                  wReserved2;

       unsigned short                  wReserved3;

       union {

              Byte                         bVal;                               // VT_UI1.

              Short                        iVal;                                // VT_I2.

              long                          lVal;                                // VT_I4.

              float                         fltVal;                              // VT_R4.

              double                      dblVal;                            // VT_R8.

              VARIANT_BOOL      boolVal;                           // VT_BOOL.

              SCODE                    scode;                            // VT_ERROR.

              CY                           cyVal;                             // VT_CY.

              DATE                       date;                               // VT_DATE.

              BSTR                       bstrVal;                           // VT_BSTR.

              DECIMAL                FAR* pdecVal;                 // VT_BYREF|VT_DECIMAL.

              IUnknown                 FAR* punkVal;                 // VT_UNKNOWN.

              IDispatch                  FAR* pdispVal;                // VT_DISPATCH.

              SAFEARRAY            FAR* parray;                   // VT_ARRAY|*.

              Byte                         FAR* pbVal;                    // VT_BYREF|VT_UI1.

              short                        FAR* piVal;                     // VT_BYREF|VT_I2.

              long                          FAR* plVal;                     // VT_BYREF|VT_I4.

              float                         FAR* pfltVal;                   // VT_BYREF|VT_R4.

              double                      FAR* pdblVal;                  // VT_BYREF|VT_R8.

              VARIANT_BOOL      FAR* pboolVal;                // VT_BYREF|VT_BOOL.

              SCODE                    FAR* pscode;                  // VT_BYREF|VT_ERROR.

              CY                           FAR* pcyVal;                  // VT_BYREF|VT_CY.

              DATE                       FAR* pdate;                    // VT_BYREF|VT_DATE.

              BSTR                       FAR* pbstrVal;                // VT_BYREF|VT_BSTR.

              IUnknown                 FAR* FAR* ppunkVal;      // VT_BYREF|VT_UNKNOWN.

              IDispatch                  FAR* FAR* ppdispVal;     // VT_BYREF|VT_DISPATCH.

              SAFEARRAY            FAR* FAR* pparray         // VT_ARRAY|*.

              VARIANT                 FAR* pvarVal;                 // VT_BYREF|VT_VARIANT.

              void                          FAR* byref;                    // Generic ByRef.

              char                         cVal;                               // VT_I1.

              unsigned short           uiVal;                              // VT_UI2.

              unsigned long            ulVal;                              // VT_UI4.

              int                            intVal;                             // VT_INT.

              unsigned int               uintVal;                           // VT_UINT.

              char FAR *               pcVal;                             // VT_BYREF|VT_I1.

              unsigned short FAR * puiVal;                            // VT_BYREF|VT_UI2.

              unsigned long FAR *  pulVal;                            // VT_BYREF|VT_UI4.

              int FAR *                  pintVal;                           // VT_BYREF|VT_INT.

              unsigned int FAR *     puintVal;                          // VT_BYREF|VT_UINT.

       };

};

  我們看到,所有簡(jiǎn)單數據類(lèi)型都可以在VARIANT中找到對應的定義,但是,在多數的基于C++的系統設計中,方法參數不會(huì )僅僅出現簡(jiǎn)單數據類(lèi)型,類(lèi)對象、對象引用、對象指針被頻繁的作為參數來(lái)傳遞。

  以類(lèi)對象、對象引用或對象指針形式存在的參數,我們稱(chēng)為復雜類(lèi)型參數。在技術(shù)方案中,所有復雜類(lèi)型參數在A(yíng)TL接口方法中一律對應接口指針,我們需要提供C++對象(或引用、指針)和ATL接口指針之間的動(dòng)態(tài)轉換功能。下文就復雜類(lèi)型作為傳入、傳出參數分別進(jìn)行討論。

  3.1. 復雜類(lèi)型的傳入參數

  ATL接口方法獲取一個(gè)接口指針參數后,如何將此接口指針轉變?yōu)镃++對象指針?對于A(yíng)TL對象,可以直接取得m_pCPPObj變量,而接口指針卻不能。所以,需要提供一種途徑,從ATL接口指針獲取ATL組件的m_pCPPObj變量值。

  我們的設計是,為每個(gè)ATL組件提供一個(gè)基接口ICPPObjSeeker,實(shí)現對綁定C++對象指針(即m_pCPPObj)的查詢(xún)方法HandleCPPObj。任意ATL接口都從該基接口派生,都可以調用HandleCPPObj方法。

  在前文就生命周期進(jìn)行討論時(shí),曾提到這樣一種情況:客戶(hù)創(chuàng )建了一個(gè)組件,然后送交集合型組件管理。在集合型組件獲取外部創(chuàng )建的組件的同時(shí),需要:

  l 取得后者的C++對象指針。集合型組件對元素組件管理的實(shí)質(zhì)是通過(guò)集合型C++對象對元素的C++對象進(jìn)行管理,而集合型ATL對象和元素ATL對象之間并沒(méi)有直接聯(lián)系

  l 修改新加入元素組件的維護標識

  因此,我們?yōu)镮CPPObjSeeker接口添加PostCPPObj方法,用于實(shí)現以上功能。

  ICPPObjSeeker接口idl定義如下所示,因為ICPPObjSeeker接口和HandleCPPObj、PostCPPObj方法實(shí)際上都應用于內部,所以使用“hidden”屬性對外隱藏:

  [

       object,

       uuid(1E9F7F79-936D-4680-9F8E-34A7DCCFF818),

       dual,

       hidden,

       helpstring("ICPPObjSeeker Interface"),

       pointer_default(unique)

  ]

interface ICPPObjSeeker : IDispatch

{

       [id(1), helpstring("取得C++對象的指針"), hidden]

              HRESULT HandleCPPObj([out, retval] long* pCPPObj);

       [id(2), helpstring("取得C++對象的指針,客戶(hù)程序不再負責對C++對象生命周期的維護"), hidden]

              HRESULT PostCPPObj([out, retval] long* pCPPObj);

};

ICPPObjSeeker接口的方法可以放在CCPP2ATLTemplateBase模板基類(lèi)中統一實(shí)現:

template <class T>

class CCPP2ATLTemplateBase :

{

              ……

       /**********************************************************

         HandleCPPObj函數,由ICPPObjSeeker接口定義,

         負責取得ATL接口中的C++對象指針

       **********************************************************/

       STDMETHODIMP HandleCPPObj(long *pCPPObj)

       {

              AFX_MANAGE_STATE(AfxGetStaticModuleState())

              *pCPPObj = (long)m_pCPPObj;

              return S_OK;

       }

       /**********************************************************

         PostCPPObj函數,由ICPPObjSeeker接口定義,

         負責取得ATL接口中的C++對象指針,

         同時(shí)標記對象為內部維護,客戶(hù)不再負責對象的生命周期管理

       **********************************************************/

       STDMETHODIMP PostCPPObj(long *pCPPObj)

       {

              AFX_MANAGE_STATE(AfxGetStaticModuleState())

              *pCPPObj = (long)m_pCPPObj;

              if (m_bInnerManage == FALSE) {

                     m_bInnerManage = TRUE;

                     m_pCPPObj->m_pAssociATLUnk = this;

                     m_pCPPObj->m_pAssociATLUnk->AddRef();

              }

              return S_OK;

       }

       };

  現在,所有的接口都不再直接從IDispatch派生,而改從ICPPObjSeeker派生,因此,IDispatch的實(shí)現也應該在實(shí)現ICPPObjSeeker接口的同一級或下級中提供。為了包容IDispatch,我們將ATL模板基類(lèi)稍作改動(dòng):

template <class T, class Q, const IID* piid, const GUID* plibid = &CComModule::m_libid>

class ATL_NO_VTABLE CCPP2ATLTemplateBase :

       public IDispatchImpl<Q, piid, plibid>

{

       ……

};

  在從該模板類(lèi)派生ATL類(lèi)時(shí),將ATL Wizard自動(dòng)生成的對IDispatch接口的實(shí)現注釋?zhuān)褂眯露x的CCPP2ATLTemplateBase,如下代碼片斷所示:

class ATL_NO_VTABLE CATLXX :

       ……,

       // 將ATL Wizard生成的對IDispatch接口的支持注釋

//     public IDispatchImpl<IXX, &IID_IXX, &LIBID_CPP2ATLLib>,

       // 添加ATL模板基類(lèi)

       public CCPP2ATLTemplateBase<CImplementXX, IXX, &IID_IXX, &LIBID_CPP2ATLLib>

{

       ……

}

  3.2. 復雜類(lèi)型的傳出參數

  從C++指針轉換為接口指針基本上不存在困難,為方便使用,我們提供一個(gè)基于本技術(shù)方案的宏定義,如下代碼所示:

/**********************************************************

  從C++指針獲取對應ATL接口的宏

  傳入:C++指針,對應的ATL類(lèi)名,接口IID

  傳出:接口指針,執行狀態(tài)HRESULT

**********************************************************/

#define CPPOBJ_TO_COM_INTERFACE(pCPPObj, CATLClass, IID_IDefine, ppInterface, hResult ) \

       { \

       ASSERT(pCPPObj != NULL); \

       if (pCPPObj->m_pAssociATLUnk != NULL) \

       { \

              hResult =  pCPPObj->m_pAssociATLUnk-> \

                     QueryInterface(IID_IDefine, (void **)ppInterface); \

              ATLASSERT(SUCCEEDED(hResult)); \

       } \

       else \

       { \

              CComObject<CcomATLClass>* pComObj; \

              hResult = CComObject<CcomATLClass>::CreateInstance(&pComObj); \

              ATLASSERT(SUCCEEDED(hResult)); \

              hResult = pComObj-> \

                     QueryInterface(IID_IDefine, (void **)ppInterface); \

              ATLASSERT(SUCCEEDED(hResult)); \

              if (hResult == S_OK) \

                     pComObj->Link2CPPObj(pCPPObj, *ppInterface); \

       }\

}

  4.   接口的繼承與多態(tài)

  C++類(lèi)的繼承應用十分廣泛,動(dòng)態(tài)化后的組件應該保留原C++類(lèi)之間的繼承關(guān)系。在我們的技術(shù)方案中,C++類(lèi)和接口一一對應,C++類(lèi)的繼承關(guān)系也應該體現在各個(gè)接口上,如下圖所示:

  

  4.1. 支持繼承的系列ATL模板基類(lèi)

  實(shí)現接口繼承的實(shí)質(zhì)是為派生ATL類(lèi)添加基接口,而為一個(gè)ATL類(lèi)添加接口的實(shí)質(zhì)則是:

  l 修改IDL文件,體現接口的繼承關(guān)系

  l 在A(yíng)TL類(lèi)中提供接口實(shí)現

  修改IDL文件很簡(jiǎn)單,只需要更改派生接口的基接口即可。在A(yíng)TL類(lèi)中添加基接口的實(shí)現倒頗費思量,我們的做法是:

  l 擴展ATL模板基類(lèi)的意義,每一個(gè)ATL組件類(lèi)都對應一個(gè)模板基類(lèi),都從該模板基類(lèi)派生

  l 派生類(lèi)的模板基類(lèi),從基類(lèi)的模板基類(lèi)中派生;CCPP2ATLTemplateBase是模板派生樹(shù)的根節點(diǎn),所有的模板都派生自CCPP2ATLTemplateBase

  l  所有的接口方法,都在對應的模板基類(lèi)中實(shí)現

  ATL派生類(lèi)繼承自它對應的模板基類(lèi),這個(gè)模板基類(lèi)又繼承自ATL基類(lèi)對應的模板基類(lèi),而在A(yíng)TL基類(lèi)的模板基類(lèi)中提供了基接口的實(shí)現。所以,ATL派生類(lèi)最終繼承了基接口的實(shí)現。C++類(lèi)、ATL類(lèi)、各模板基類(lèi)的繼承關(guān)系如下圖所示:

  

  假定IBaseItf是基接口,IInheritItf是派生接口。ATL基類(lèi)對應的模板基類(lèi)定義如下:

/****************************************************************************

  模板類(lèi)CAtlBaseItf,提供了IBaseItf的實(shí)現,

  用于將IBaseItf接口作為基接口共供其它接口繼承

****************************************************************************/

template <class T, class Q, const IID* piid, const GUID* plibid = &CComModule::m_libid>

class ATL_NO_VTABLE CAtlBaseItf : public CCPP2ATLTemplateBase<T, Q, piid, plibid>

{

public:

       // 基接口方法“BaseFunc”,在此模板類(lèi)內實(shí)現

       STDMETHOD(BaseFunc)()

       {

              m_pCPPObj->BaseFunc();

              return S_OK;

       }

};

ATL派生類(lèi)對應的模板基類(lèi)定義如下:

/****************************************************************************

  模板類(lèi)CAtlInheritItf,繼承了基接口IBaseItf方法的實(shí)現,

  同時(shí)提供了IInheritItf的實(shí)現,可以將IInheritItf接口作為基接口共供其它接口繼承

****************************************************************************/

template <class T, class Q, const IID* piid, const GUID* plibid = &CComModule::m_libid>

class ATL_NO_VTABLE CAtlInheritItf : public CAtlBaseItf<T, Q, piid, plibid>

{

public:

       // 派生接口方法“InheritFunc”,在此模板類(lèi)內實(shí)現

       STDMETHOD(InheritFunc)()

       {

              m_pCPPObj->InheritFunc();

              return S_OK;

       }

};

更改IInheritItf接口的IDL定義:

[

       object,

       uuid(8F3902DF-DA55-4802-AB8A-958AFF45B2F4),

       dual,

       helpstring("IBaseItf Interface"),

       pointer_default(unique)

]

// 基接口從ICPPObjSeeker派生

interface IBaseItf : ICPPObjSeeker

{

       [id(1), helpstring("IBaseItf Method")] HRESULT BaseFunc();

};

[

       object,

       uuid(AFEBD472-4BEC-45CE-A5A2-E37537C4744A),

       dual,

       helpstring("IInheritItf Interface"),

       pointer_default(unique)

]

// IInheritItf接口從IBaseItf接口派生

interface IInheritItf : IBaseItf

{

       [id(11), helpstring("IInheritItf Method")] HRESULT InheritFunc();

};

最后,更改ATL派生類(lèi)的模板基類(lèi):

class ATL_NO_VTABLE CATLInherit :

       ……,

       public CAtlInheritItf<CInheritItfImplement, IInheritItf, &IID_IInheritItf, &LIBID_CPP2ATLLib>

{

       ……

};

  現在,通過(guò)IInheritItf,我們可以使用IBaseItf的所有方法,實(shí)現了接口的繼承。

  4.2. 接口的多態(tài)性

  在實(shí)現接口的繼承后,要展現接口的多態(tài)性就很容易了,只需在A(yíng)TL派生類(lèi)聲明的接口映射表中添加基接口表項即可:

class ATL_NO_VTABLE CATLInherit :

       ……,

       public CAtlInheritItf<CInheritItfImplement, IInheritItf, &IID_IInheritItf, &LIBID_CPP2ATLLib>

{

       ……

       BEGIN_COM_MAP(CInheritItf)

       COM_INTERFACE_ENTRY(IInheritItf)

       COM_INTERFACE_ENTRY(IBaseItf)

       ……

END_COM_MAP()

       ……

};

  就象C++中基類(lèi)指針所展現的多態(tài)性一樣,一個(gè)“IBaseItf *”型指針可以完全操縱IInheritItf接口,而不需要知道真正的接口類(lèi)型。

  5.  

  至此,我們的技術(shù)方案全部介紹完畢。C++基類(lèi)CCPP2ATLObjBase、ATL模板基類(lèi)CCPP2ATLTempBase和基接口ICPPObjSeeker是方案中的關(guān)鍵技術(shù)。CCPP2ATLObjBase配合CCPP2ATLTempBase,完善了組件對象生命周期的機制;通過(guò)基接口ICPPObjSeeker,我們可以從任意接口反向查詢(xún)C++對象;CCPP2ATLTempBase提供了C++對象和ATL組件的自由綁定功能,封裝了IDispatch接口的實(shí)現,而進(jìn)一步定義的ATL模板基類(lèi)繼承體系則極大的方便了接口的自由繼承。

  在本文快結束的時(shí)候,我們不得不特別提到Microsoft的“.Net FrameWork”!.Net”開(kāi)發(fā)框架的推出,的確解決了COM技術(shù)的許多困惑,也包括本技術(shù)方案所要解決的一些技術(shù)問(wèn)題。然而“.Net Framework”是一個(gè)“改朝換代”的變化,要想一步將原來(lái)基于C++的系統(尤其是大型系統)完全移植到“.Net”平臺上是不可想象的,其工作量不亞于重新開(kāi)發(fā),所以Microsoft特別推薦從COM技術(shù)到“.Net”平臺的平滑移植。由此看來(lái),本文提出的動(dòng)態(tài)組件化的技術(shù)更顯得可貴,它從工程化的角度,著(zhù)眼于實(shí)際應用,解決了從面向對象的C++到基于組件的COM技術(shù)的許多問(wèn)題,既充分保護了原有系統的積累,又為這些系統搭上日益發(fā)展的“.Net”快車(chē)提供了可能。


  參考文獻

  《COM原理與應用》,潘愛(ài)民 著(zhù),清華大學(xué)出版社

  《COM本質(zhì)論(Essential COM)》,Don Box 著(zhù),潘愛(ài)民 譯,中國出版社

  《深入解析ATL(ATL Internals)》,Brent Rector、Chris Sells 著(zhù),潘愛(ài)民、新語(yǔ) 譯,中國電力出版社

  《設計模式-可復用面向對象軟件的基礎(Design Patterns-Elements of Reusable Object-Oriented Software)》,Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides 著(zhù),李英軍、馬曉星、蔡敏、劉建中 等譯

【C++類(lèi)的動(dòng)態(tài)組件化技術(shù)】相關(guān)文章:

基于COM技術(shù)的公式計算組件的開(kāi)發(fā)與實(shí)現11-23

硬件密碼組件與軟件密碼組件的比較研究03-18

動(dòng)態(tài)環(huán)境下的組織柔性化戰略03-23

企業(yè)治理信息系統組件化信息資源分析與設計03-23

COM組件技術(shù)在現場(chǎng)總線(xiàn)控制系統組態(tài)軟件中的應用03-18

Excel Web組件的應用(一)03-07

淺析化學(xué)工程技術(shù)及發(fā)展動(dòng)態(tài)12-02

淺談山區高速公路動(dòng)態(tài)設計與信息化施工03-01

基于組件的三維CAD系統開(kāi)發(fā)的關(guān)鍵技術(shù)研究03-19

激情欧美日韩一区二区,浪货撅高贱屁股求主人调教视频,精品无码成人片一区二区98,国产高清av在线播放,色翁荡息又大又硬又粗视频