中文字幕在线一区二区在线,久久久精品免费观看国产,无码日日模日日碰夜夜爽,天堂av在线最新版在线,日韩美精品无码一本二本三本,麻豆精品三级国产国语,精品无码AⅤ片,国产区在线观看视频

      C++類的動態組件化技術

      時間:2024-10-12 04:18:33 計算機應用畢業論文 我要投稿
      • 相關推薦

      C++類的動態組件化技術

        論文關鍵詞:COM組件 接口 生命周期 C++類 ATL組件類 C++基類 ATL模板基類 繼承

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

        1. 問題的提出

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

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

        然而,COM技術帶來全新的軟件設計和開發模式的同時,也帶來了新的問題。

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

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

        一個自然而然的想法是,為每一個C++類開發一個只暴露一個接口的COM組件,將原C++類的每個public方法都對應于該接口的一個方法,接口方法的實現可以簡單的調用相對應的C++類方法即可。這樣,程序由原有的C++類控制,但COM層的封裝則由組件提供。基本思路如下圖所示:

        

        本文就這一技術展開討論,最終提供一套由普通C++類平滑過渡到COM組件的完整解決方案。我們選用ATL(Active Template Library,活動模板庫,簡稱ATL)作為COM組件的開發工具,開發環境為Visual Studio 6.0。如沒有特殊說明,下文中的“C++類”指沒有組件特性C++類,“C++對象”指C++類的實例;“ATL組件類”指用于包裝的ATL類,“ATL對象”指ATL組件類的實例。

        2. 用ATL包裝C++類

        按上述思路將C++對象動態組件化后,所得的組件實際上由兩部分組成:ATL組件對象和綁定的C++對象。兩者的生命周期互相牽制,但要保持一致。生命周期的是C++類動態組件化的首要難點。

        C++類分為兩種,一種是簡單的C++類,一種是集合型的C++類。集合型的C++對象管理一組C++對象,負責其創建和刪除,維護它們的生命周期。下面,分別就簡單C++類和集合型C++類的組件化技術進行說明,展示解決方案的核心技術。

        2.1. 簡單C++類的組件化

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

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

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

        我們可以在ATL組件類初始化時創建一個C++類,用成員變量m_pCPPObj記錄,在析構時刪除,從而實現ATL組件類和C++類的天然綁定。但出于靈活性考慮,使得ATL組件對象可以綁定任意C++類的對象,我們為ATL組件類添加一個綁定函數Link2CPPObj(CImplement* pObj)。

        在ATL組件類的構造函數內,創建一個C++對象,用m_pCPPObj記錄。

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

        在ATL組件類的的析構函數內,刪除其綁定的C++對象。由構造函數和Link2CPPObj函數的定義可知,m_pCPPObj指針總是有意義的。

        簡單C++類組件化的思想如下圖所示:

        

        2.2. 集合型C++類的組件化

        集合型C++類的情況有所不同。

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

        為了解決這個問題,我們需要在C++對象被刪除時,能將ATL對象同時刪除;而在ATL對象的引用計數為0需要刪除自身時,也能把C++對象刪除。可行的解決方案是:

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

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

        現在,技術方案如下圖所示:

        

        2.3. 內部創建的組件和外部創建的組件

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

        l 由客戶直接創建

        l 由客戶調用集合型組件的接口方法間接創建

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

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

        

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

        2.4. C++基類

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

        

        實現代碼如下所示:

      class CCPP2ATLObjBase

      {

             CCPP2ATLObjBase ();

      public:

             // IUnknown指針,反指向封裝該CPP類的接口

             IUnknown*    m_pAssociATLUnk;

      protected:

             virtual ~ CCPP2ATLObjBase ();

      };

      CCPP2ATLObjBase::CCPP2ATLObjBase()

      {

             // 將IUnknown指針初始化為0

             m_pAssociATLUnk = NULL;

      }

      CCPP2ATLObjBase::~CCPP2ATLObjBase()

      {

             // CPP類的對象析構時,Release對接口的引用

             if (m_pAssociATLUnk)

                    m_pAssociATLUnk->Release();

      }

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

      class CImplement : public CCPP2ATLObjBase

      {

             ……

      };

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

        2.5. ATL模板基類

        通過以上分析,我們發現,所有的ATL組件類都需要實現一些相同的功能:

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

        l 提供一個Link2CPPObj函數

        l 在構造函數中創建一個綁定C++類的對象

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

        

      實現代碼如下所示:

      template <class T>

      class CCPP2ATLTemplateBase :

      {

      protected:

             // C++類指針

             T*          m_pCPPObj;

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

             BOOL     m_bInnerManage;

      public:

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

               模板的構造函數,實現如下功能:

               1、new一個C++實現類對象

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

               3、將C++類中對ATL接口的反指指針設置為空

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

             CAtlCPP2ATLTemplateBase()

             {

                    m_pCPPObj = new T;

                    m_bInnerManage = FALSE;

                    m_pCPPObj->m_pAssociATLUnk = NULL;

             }

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

               析構ATL對象時,如果該ATL對象是由外部創建的,

               則顯式的刪除C++對象

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

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

             virtual ~CAtlCPP2ATLTemplateBase()

             {

                    if (!m_bInnerManage) {

                           if (m_pCPPObj)

                                  delete m_pCPPObj;

                    }

             }

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

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

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

               2、將ATL對象的內部維護標識設為TRUE

               3、設置C++基類中的接口指針成員

               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();

             }

      };

      然后,每個ATL類都從該模板類派生,如下代碼片斷所示:

      class ATL_NO_VTABLE CATLXX :

             ……,

             // 添加ATL模板基類

             public CCPP2ATLTemplateBase<CImplementXX>

      {

             ……

      }

        3.   C++參數類型的自動化包裝

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

        在基于COM的自動化(Automation)技術中,Microsoft提供了一套自動化兼容的數據類型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.

             };

      };

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

        以類對象、對象引用或對象指針形式存在的參數,我們稱為復雜類型參數。在技術方案中,所有復雜類型參數在ATL接口方法中一律對應接口指針,我們需要提供C++對象(或引用、指針)和ATL接口指針之間的動態轉換功能。下文就復雜類型作為傳入、傳出參數分別進行討論。

        3.1. 復雜類型的傳入參數

        ATL接口方法獲取一個接口指針參數后,如何將此接口指針轉變為C++對象指針?對于ATL對象,可以直接取得m_pCPPObj變量,而接口指針卻不能。所以,需要提供一種途徑,從ATL接口指針獲取ATL組件的m_pCPPObj變量值。

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

        在前文就生命周期進行討論時,曾提到這樣一種情況:客戶創建了一個組件,然后送交集合型組件管理。在集合型組件獲取外部創建的組件的同時,需要:

        l 取得后者的C++對象指針。集合型組件對元素組件管理的實質是通過集合型C++對象對元素的C++對象進行管理,而集合型ATL對象和元素ATL對象之間并沒有直接聯系

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

        因此,我們為ICPPObjSeeker接口添加PostCPPObj方法,用于實現以上功能。

        ICPPObjSeeker接口idl定義如下所示,因為ICPPObjSeeker接口和HandleCPPObj、PostCPPObj方法實際上都應用于內部,所以使用“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++對象的指針,客戶程序不再負責對C++對象生命周期的維護"), hidden]

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

      };

      ICPPObjSeeker接口的方法可以放在CCPP2ATLTemplateBase模板基類中統一實現:

      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++對象指針,

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

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

             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的實現也應該在實現ICPPObjSeeker接口的同一級或下級中提供。為了包容IDispatch,我們將ATL模板基類稍作改動:

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

      class ATL_NO_VTABLE CCPP2ATLTemplateBase :

             public IDispatchImpl<Q, piid, plibid>

      {

             ……

      };

        在從該模板類派生ATL類時,將ATL Wizard自動生成的對IDispatch接口的實現注釋,而使用新定義的CCPP2ATLTemplateBase,如下代碼片斷所示:

      class ATL_NO_VTABLE CATLXX :

             ……,

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

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

             // 添加ATL模板基類

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

      {

             ……

      }

        3.2. 復雜類型的傳出參數

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

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

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

        傳入:C++指針,對應的ATL類名,接口IID

        傳出:接口指針,執行狀態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.   接口的繼承與多態

        C++類的繼承應用十分廣泛,動態化后的組件應該保留原C++類之間的繼承關系。在我們的技術方案中,C++類和接口一一對應,C++類的繼承關系也應該體現在各個接口上,如下圖所示:

        

        4.1. 支持繼承的系列ATL模板基類

        實現接口繼承的實質是為派生ATL類添加基接口,而為一個ATL類添加接口的實質則是:

        l 修改IDL文件,體現接口的繼承關系

        l 在ATL類中提供接口實現

        修改IDL文件很簡單,只需要更改派生接口的基接口即可。在ATL類中添加基接口的實現倒頗費思量,我們的做法是:

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

        l 派生類的模板基類,從基類的模板基類中派生;CCPP2ATLTemplateBase是模板派生樹的根節點,所有的模板都派生自CCPP2ATLTemplateBase

        l  所有的接口方法,都在對應的模板基類中實現

        ATL派生類繼承自它對應的模板基類,這個模板基類又繼承自ATL基類對應的模板基類,而在ATL基類的模板基類中提供了基接口的實現。所以,ATL派生類最終繼承了基接口的實現。C++類、ATL類、各模板基類的繼承關系如下圖所示:

        

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

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

        模板類CAtlBaseItf,提供了IBaseItf的實現,

        用于將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”,在此模板類內實現

             STDMETHOD(BaseFunc)()

             {

                    m_pCPPObj->BaseFunc();

                    return S_OK;

             }

      };

      ATL派生類對應的模板基類定義如下:

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

        模板類CAtlInheritItf,繼承了基接口IBaseItf方法的實現,

        同時提供了IInheritItf的實現,可以將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”,在此模板類內實現

             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派生類的模板基類:

      class ATL_NO_VTABLE CATLInherit :

             ……,

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

      {

             ……

      };

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

        4.2. 接口的多態性

        在實現接口的繼承后,要展現接口的多態性就很容易了,只需在ATL派生類聲明的接口映射表中添加基接口表項即可:

      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++中基類指針所展現的多態性一樣,一個“IBaseItf *”型指針可以完全操縱IInheritItf接口,而不需要知道真正的接口類型。

        5.  

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

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


        參考文獻

        《COM原理與應用》,潘愛民 著,清華大學出版社

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

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

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

      【C++類的動態組件化技術】相關文章:

      基于COM技術的公式計算組件的開發與實現11-23

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

      動態環境下的組織柔性化戰略03-23

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

      COM組件技術在現場總線控制系統組態軟件中的應用03-18

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

      淺析化學工程技術及發展動態12-02

      淺談山區高速公路動態設計與信息化施工03-01

      基于組件的三維CAD系統開發的關鍵技術研究03-19

      主站蜘蛛池模板: 国产a视频一区二区三区| 色噜噜狠狠色综合欧洲| 国产精品天干天干在线观蜜臀| 18禁国产美女白浆在线| 资兴市| 国产精品一区二区三区精品| 亚洲一区极品美女写真在线看| 少妇bbwbbw高潮| 夏河县| 日韩精品一区二区三区四区| 国产高清黄色在线观看91| 国产亚洲成人精品一区| 财经| 康定县| 成人免费观看在线播放视频| 蜜桃视频福利在线观看| 加勒比熟女精品一区二区av| 国产自精品在线| 蜜桃av一区二区高潮久久| 性感人妻中文字幕在线| 免费一级a毛片在线播出| 锡林浩特市| 邵东县| 芒康县| 中文字幕人妻av蜜臀| 亚洲国产国语对白在线字幕| 久久久老熟女一区二区三区| 日本中文字幕一区二区视频| 久久免费网站91色网站| 穆棱市| 潢川县| 精品国产亚洲av麻豆尤物| 在线毛片一区二区不卡视频| 日本视频精品一区二区| 孟州市| 塔河县| 午夜不卡亚洲视频| a午夜国产一级黄片| 久久久久综合一本久道| 中国女人a毛片免费全部播放| 双辽市|