包容和聚合实际上是一个组件使用另一个组件的技术。对于这两个组件,可以把第一个组件称为外部组件,被使用组件称为内部组件。
1、包容简介
COM包容同C++包容是相似的。但是在COM中,同其他内容类似,包容也是在接口级完成的。外部组件包含指向内部组件接口的指针。此时外部组件只是内部组件的一个客户,它将使用内部组件的接口来实现自己的接口。
外边组件也可以通过将调用转发给内部组件的方法重新实现内部组件所支持的某个接口(适配器模式?很像啊)。并且外部组件还可以在内部组件代码的前后加上一些代码以对接口进行改造。
2、聚合简介
聚合是包容的一个特例。当一个外部组件聚合了某个内部组件的的一个接口时,它并没有像包容那样重新实现此接口并明确地将调用请求转发给内部组件。相反,外部组件将直接把内部组件的接口返回给客户。使用此方法,外部组件将无需重现实现并转发接口中的所有函数。
但是使用此方式,外部组件将无法对接口中的函数进行任何改造。当外部组件将内部组件的接口返回给客户之后,客户就直接同内部组件打交道了。但是此时客户不应该知道他是在同两个不同的组件交互,否则将无法满足封装的要求。这种使得外部组件和内部组件看起来像一个组件的做法是成功的进行聚合的关键。
以下代码只列出了关键部分,其它部分省略。
包容 外部组件包含指向内部组件接口的指针,此时外部组件只是内部组件的一个客户。外部组件可通过将调用转发给内部组件来重新实现内部组件的某个接口,还可在内部组件代码前后加上一些代码对接口改造。
组件1中的新成员m_pIY保存了指向所包容的组件2中IY接口的指针
外部组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 // // Component A // class CA : public IX, public IY //@N { public: // IUnknown virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ; virtual ULONG __stdcall AddRef() ; virtual ULONG __stdcall Release() ; // Interface IX virtual void __stdcall Fx() { cout << "Fx" << endl ;} // Interface IY virtual void __stdcall Fy() { m_pIY->Fy() ;} //@N // Constructor CA() ; // Destructor ~CA() ; // Initialization function called by the class factory // to create the contained component HRESULT __stdcall Init() ; //@N private: // Reference count long m_cRef ; // 被包容的组件 IY* m_pIY ; } ; // // Constructor // CA::CA() : m_cRef(1), m_pIY(NULL) //@N 内部组件初始化 { ::InterlockedIncrement(&g_cComponents) ; } // // Destructor // CA::~CA() { ::InterlockedDecrement(&g_cComponents) ; trace("Destroy self.") ; // 释放内部组件 @N if (m_pIY != NULL) { m_pIY->Release() ; } } // 创建内部组件 HRESULT __stdcall CA::Init() { trace("Create contained component.") ; //外部组件请求了内部组件IY接口的指针,若调用成功,被保存在m_pIY中 HRESULT hr = ::CoCreateInstance(CLSID_Component2, NULL, CLSCTX_INPROC_SERVER, IID_IY, (void**)&m_pIY) ; if (FAILED(hr)) { trace("Could not create contained component.") ; return E_FAIL ; } else { return S_OK ; } }
外部组件的类厂 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 // // IClassFactory implementation // HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) { // Cannot aggregate if (pUnknownOuter != NULL) { return CLASS_E_NOAGGREGATION ; } // 创建外部组件 CA* pA = new CA ; if (pA == NULL) { return E_OUTOFMEMORY ; } // 创建内部组件 @N HRESULT hr = pA->Init() ; if (FAILED(hr)) { // 如何失败,则删除 pA->Release() ; return hr ; } // Get the requested interface. hr = pA->QueryInterface(iid, ppv) ; pA->Release() ; return hr ; }
聚合 为了实现 聚合,内部组件需要实现两个不同的接口,其中一个是非代理IUknown接口:按通常的方式实现内部组件的IUknown接口。另一个是代理接口:未被聚合时将函数调用转发给非代理接口,被聚合时转发给外部组件的IUknown接口。
聚合情况下,代理IUknown接口将调用外部组件的IUknown实现。外部组件也可以内部组件的非代理IUknown接口来控制组件的生命期。
外部组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 // // Component A // class CA : public IX // public IY @N { public: // IUnknown virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ; virtual ULONG __stdcall AddRef() ; virtual ULONG __stdcall Release() ; // Interface IX virtual void __stdcall Fx() { cout << "Fx" << endl ;} /* @N Component1 aggregates instead of implementing interface IY. // Interface IY virtual void __stdcall Fy() { m_pIY->Fy() ;} */ // Constructor CA() ; // Destructor ~CA() ; // Initialization function called by the class factory // to create the contained component HRESULT __stdcall Init() ; // @N private: // Reference count long m_cRef ; // Pointer to the aggregated component's IY interface // (We do not have to retain an IY pointer. However, we // can use it in QueryInterface.) IY* m_pIY ; // @N // Pointer to inner component's IUnknown IUnknown* m_pUnknownInner ; // @N } ; // // Destructor // 在外部组件的析构中释放内部组件接口 CA::~CA() { ::InterlockedDecrement(&g_cComponents) ; trace("Destroy self.") ; // 恢复引用计数,保证组件不会试图再次将自己释放掉 m_cRef = 1 ; // 因为对内部组件的Release将会导致对外部组件的Release调用 IUnknown* pUnknownOuter = this ; pUnknownOuter->AddRef() ; // 将外部组件释放掉 m_pIY->Release() ; // 将内部组件释放掉 if (m_pUnknownInner != NULL) // @N { m_pUnknownInner->Release() ; } } // 创建内部组件 HRESULT __stdcall CA::Init() { // Get the pointer to the outer unknown. // Since this component is not aggregated, the outer unknown // is the same as the this pointer. IUnknown* pUnknownOuter = this ; trace("Create inner component.") ; HRESULT hr = ::CoCreateInstance(CLSID_Component2, pUnknownOuter, // 外部组件IUnknown接口 @N CLSCTX_INPROC_SERVER, IID_IUnknown, // IUnknown,当聚合时 @N (void**)&m_pUnknownInner) ; if (FAILED(hr)) { trace("Could not create contained component.") ; return E_FAIL ; } //需要在创建了内部组件之后再请求其IID_IY接口 //QueryInterface会调用AddRef,由于内部组件是被聚合的,会被转发给外部组件的AddRef //因此,会导致外部组件的引用计数增加,而内部组件引用计数不变 trace("Get the IY interface from the inner component.") ; hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ; //@N if (FAILED(hr)) { trace("Inner component does not support interface IY.") ; m_pUnknownInner->Release() ; return E_FAIL ; } // 为了实现正确计数,因为创建内部组件会导致外部组件计数增大 pUnknownOuter->Release() ; //@N return S_OK ; } // // IUnknown implementation // HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv) { if (iid == IID_IUnknown) { *ppv = static_cast<IUnknown*>(this) ; } else if (iid == IID_IX) { *ppv = static_cast<IX*>(this) ; } else if (iid == IID_IY) { trace("Return inner component's IY interface.") ; #if 1 // 得到指向内部接口的指针 return m_pUnknownInner->QueryInterface(iid,ppv) ; //@N #else // Or you can return a cached pointer. *ppv = m_pIY ; //@N // Fall through so it will get AddRef'ed #endif } else { *ppv = NULL ; return E_NOINTERFACE ; } reinterpret_cast<IUnknown*>(*ppv)->AddRef() ; return S_OK ; }
外部组件的类厂 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 // // IClassFactory implementation // HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) { // Cannot aggregate if (pUnknownOuter != NULL) { return CLASS_E_NOAGGREGATION ; } // Create component. CA* pA = new CA ; if (pA == NULL) { return E_OUTOFMEMORY ; } // Initialize the component. @N HRESULT hr = pA->Init() ; if (FAILED(hr)) { // Initialization failed. Delete component. pA->Release() ; return hr ; } // Get the requested interface. hr = pA->QueryInterface(iid, ppv) ; pA->Release() ; return hr ; }
内部组件需要实现的接口—非代理IUknown接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 // // 非代理 IUnknown 接口 @N // struct INondelegatingUnknown { virtual HRESULT __stdcall NondelegatingQueryInterface(const IID&, void**) = 0 ; virtual ULONG __stdcall NondelegatingAddRef() = 0 ; virtual ULONG __stdcall NondelegatingRelease() = 0 ; } ; // // IUnknown implementation // HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid, void** ppv) { if (iid == IID_IUnknown) { //将this指针换成了INondelegatingUnknown指针,重要! //保证返回的是一个非代理IUknown指针 //当非代理接口指针查询IID_IUknown接口时,返回的将总是一个指向 //其自身的指针。若不进行转换,返回的将是指向代理IUknown接口的指针 *ppv = static_cast<INondelegatingUnknown*>(this) ; // @N } else if (iid == IID_IY) { *ppv = static_cast<IY*>(this) ; } else { *ppv = NULL ; return E_NOINTERFACE ; } reinterpret_cast<IUnknown*>(*ppv)->AddRef() ; return S_OK ; }
内部组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 // // Component // class CB : public IY, public INondelegatingUnknown { public: // 代理 IUnknown // 以内联方式实现 // 只要将调用请求转发给外部IUknown接口或非代理IUnknown接口即可 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) { trace("Delegate QueryInterface.") ; return m_pUnknownOuter->QueryInterface(iid, ppv) ; } virtual ULONG __stdcall AddRef() { trace("Delegate AddRef.") ; return m_pUnknownOuter->AddRef() ; } virtual ULONG __stdcall Release() { trace("Delegate Release.") ; return m_pUnknownOuter->Release() ; } // 非代理 IUnknown virtual HRESULT __stdcall NondelegatingQueryInterface(const IID& iid, void** ppv) ; virtual ULONG __stdcall NondelegatingAddRef() ; virtual ULONG __stdcall NondelegatingRelease() ; // Interface IY virtual void __stdcall Fy() { cout << "Fy" << endl ;} // Constructor CB(IUnknown* m_pUnknownOuter) ; // Destructor ~CB() ; private: long m_cRef ; //引用计数 //当此组件被聚合时,指向外部IUknown接口 IUnknown* m_pUnknownOuter ; } ; // // Constructor // 将外部IUknown的指针传给内部组件的构造函数,初始化m_pUnknownOuter CB::CB(IUnknown* pUnknownOuter) : m_cRef(1) { ::InterlockedIncrement(&g_cComponents) ; //若此组件未被聚合,将m_pUnknownOuter设为指向非代理IUknown接口 if (pUnknownOuter == NULL) { trace("Not aggregating; delegate to nondelegating IUnknown.") ; m_pUnknownOuter = reinterpret_cast<IUnknown*> (static_cast<INondelegatingUnknown*> (this)) ; } //若此组件被聚合,指向外部IUKnown接口 else { trace("Aggregating; delegate to outer IUnknown.") ; m_pUnknownOuter = pUnknownOuter ; } }
内部组件的类厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // // IClassFactory implementation // HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) { //当pUnknownOuter非空,表示外部组件想进行聚合 //iid必须为IID_IUnknown,因为当组件被聚合时,只能返回一个IUknown接口 if ((pUnknownOuter != NULL) && (iid != IID_IUnknown)) //@N { return CLASS_E_NOAGGREGATION ; } // Create component. CB* pB = new CB(pUnknownOuter) ; // @N if (pB == NULL) { return E_OUTOFMEMORY ; } //获取新创建的内部组件中客户所请求的接口 //并非调用QueryInterface //因为类厂需要返回一个指向非代理IUknown接口的指针 HRESULT hr = pB->NondelegatingQueryInterface(iid, ppv) ; //@N pB->NondelegatingRelease() ; return hr ; }
客户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 // // Client.cpp - client implementation // #include <iostream.h> #include <objbase.h> #include "Iface.h" void trace(const char* msg) { cout << "Client: \t" << msg << endl ;} // // main function // int main() { // Initialize COM Library CoInitialize(NULL) ; trace("Get interface IX from Component 1.") ; IX* pIX = NULL ; HRESULT hr = ::CoCreateInstance(CLSID_Component1, NULL, CLSCTX_INPROC_SERVER, IID_IX, (void**)&pIX) ; if (SUCCEEDED(hr)) { trace("Succeeded creating component.") ; pIX->Fx() ; trace("Get interface IY from IX.") ; IY* pIY = NULL ; hr = pIX->QueryInterface(IID_IY, (void**)&pIY) ; if (SUCCEEDED(hr)) { trace("Succeeded getting interface IY from IX.") ; pIY->Fy() ; trace("Get interface IX from IY.") ; IX* pIX2 = NULL ; hr = pIY->QueryInterface(IID_IX, (void**)&pIX2); if (SUCCEEDED(hr)) { trace("Succeeded getting interface IX from IY.") ; pIX2->Release() ; } else { trace("Error! Should have gotten interface IX.") ; } pIY->Release() ; } else { trace("Could not get interface IY.") ; } pIX->Release() ; } else { cout << "Could not create component: " << hex << hr << endl ; } // Uninitialize COM Library CoUninitialize() ; return 0 ; }