第8章
“实现继承”,指的是继承基类代码或实现,“接口继承”,指的是继承基类类型或接口。 COM支持的继承是接口继承,不支持实现继承。实现继承会导致一个对象的实现同另外一个对象实现关联起来,当基类修改后,派生类也就必须被修改,甚至客户端的程序也需要修改,这显然有悖于COM组件编程的基本思想。
在C++中,对类的改造用包容和继承来实现的。在COM中,对组件的改造是使用包容和聚合来实现的,包容和聚合都是在接口级实现的。
包容
包容,是一个组件使用另外一个组件的技术,分别成为外部组件和内部组件。
包容的情况下,外部组件包含指向内部组件接口的指针,外部组件只是内部组件的一个客户。外部组件使用内部组件的接口来实现它自己的接口,并且可以在接口的实现函数加上它对内部组件接口实现的修改。
组件的包容类似c++的包容。
示意图如下
包容的实现
在下面的例子中,组件1(Component1)是一个实现了IX和IY接口的外部组件,它复用了组件2(组件1包容的内部组件)对IY接口的实现。源码与第七章的没多大差别,只是在组建1中加入了一个Init()的函数,用来创建组件2中的IY接口指针。组件2是一个典型的COM组件。当客户向Component1请求IY接口时,Component1将返回其IY接口的一个指针。当客户调用Component1中的IY接口时,Component1通过如下的代码将把这些调用请求转发给Component2。
void __stdcall CA::Fy() { m_pIy->Fy(); }当Component1将自己销毁时,它将调用m_pIy上的Release,以使Component2将自己从内存释放。
Component1的类厂所做的修改,只是在类厂创建好Component1之后加上对Component1的Init()的调用,用来创建组件2。
本章代码
组件2部分:cmpnt2.cpp
// //cmpnt2.cpp //use: cl /LD cmpnt2.cpp guids.cpp registry.cpp cmpnt2.def uuid.lib ole32.lib advapi32.lib // regsvr32 /s cmpnt2.dll // ole32.lib COMLIBRARY advapi32.lib REGISTER #include <objbase.h> #include "iface.h" #include "registry.h" #include <iostream> #include <string> using namespace std; //global function // static HMODULE g_hModule = NULL; //COMPONENT2 MODULE HANDLE static long g_lComponent = 0; //COMPONENT2 COUNT static long g_lServerLocks = 0; //CFactory COUNT //Friendly Name const char g_szFriendlyName[] = "Inside COM, Chapter 8 Example 1, Component 2"; //Version-independent ProgID const char g_szVerIndProgID[] = "InsideCOM.chap08.ex1.cmpnt2"; //ProgID const char g_szProgID[] = "InsideCOM.chap08.ex1.cmpnt2.1"; //trace function void trace(string msg) { cout<<msg<<endl; } //////////////////////////////////////////// //class CB // class CB : public IY { public: virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv); virtual ULONG __stdcall AddRef(); virtual ULONG __stdcall Release(); virtual void __stdcall Fy() {cout<<"CB::Fy"<<endl;} CB(); ~CB(); private: long m_cRef; }; CB::CB():m_cRef(1) { InterlockedIncrement(&g_lComponent); } CB::~CB() { trace("component2 destroy self"); InterlockedDecrement(&g_lComponent); } ULONG __stdcall CB::AddRef() { return InterlockedIncrement(&m_cRef); } ULONG __stdcall CB::Release() { if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; } return m_cRef; } HRESULT __stdcall CB::QueryInterface(const IID& iid, void **ppv) { if(iid == IID_IUnknown) { *ppv = static_cast<IY*>(this); } else if(iid == IID_IY) { *ppv = static_cast<IY*>(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK; } ///////////////////////////////////////////// //class factory // class CFactory : public IClassFactory { public: //interface iunknown virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv); virtual ULONG __stdcall AddRef(); virtual ULONG __stdcall Release(); //interface iclassfactory virtual HRESULT __stdcall CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv); virtual HRESULT __stdcall LockServer(BOOL bLock); CFactory(); ~CFactory(); private: long m_cRef; }; CFactory::CFactory():m_cRef(1) { } CFactory::~CFactory() { trace("component2 cfactory : destroy self"); } HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void **ppv) { if(iid == IID_IUnknown || iid == IID_IClassFactory) { *ppv = static_cast<IClassFactory*>(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK; } ULONG __stdcall CFactory::AddRef() { return InterlockedIncrement(&m_cRef); } ULONG __stdcall CFactory::Release() { if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; } return m_cRef; } //CreateInstance HRESULT __stdcall CFactory::CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv) { if(pIUnknownOuter != NULL) { trace("no aggregation"); return CLASS_E_NOAGGREGATION; } //Create Compnent2 CB *pB = new CB(); if(pB == NULL) { return E_OUTOFMEMORY; } //Get Request interface HRESULT hr = pB->QueryInterface(iid, ppv); //Release IUnknown interface pB->Release(); return hr; } HRESULT __stdcall CFactory::LockServer(BOOL bLock) { if(bLock == TRUE) { InterlockedIncrement(&g_lServerLocks); } else { InterlockedDecrement(&g_lServerLocks); } return S_OK; } //////////////////////////////////////// //export functions // //Get Interface IClassFactory STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv) { if(clsid != CLSID_Component2) return CLASS_E_CLASSNOTAVAILABLE; CFactory *pFactory = new CFactory(); if(pFactory == NULL) { return E_OUTOFMEMORY; } HRESULT hr = pFactory->QueryInterface(iid, ppv); pFactory->Release(); return hr; } STDAPI DllCanUnloadNow() { if(g_lComponent == 0 && g_lServerLocks == 0) return S_OK; else return S_FALSE; } STDAPI DllRegisterServer() { return RegisterServer(g_hModule, CLSID_Component2, g_szFriendlyName, g_szVerIndProgID, g_szProgID); } STDAPI DllUnRegisterServer() { return UnregisterServer(CLSID_Component2, g_szVerIndProgID, g_szProgID); } BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved) { if(dwReason == DLL_PROCESS_ATTACH) { g_hModule = hModule; } return TRUE; }
LIBRARY cmpnt2.dll DESCRIPTION 'Chapter08 Component2' EXPORTS DllGetClassObject @2 private DllCanUnloadNow @3 private DllRegisterServer @4 private DllUnRegisterServer @5 private
// //cmpnt1.cpp //use: cl /LD cmpnt1.cpp guids.cpp registry.cpp cmpnt2.def uuid.lib ole32.lib advapi32.lib // regsvr32 /s cmpnt1.dll // ole32.lib COMLIBRARY advapi32.lib REGISTER #include <objbase.h> #include "iface.h" #include "registry.h" #include <iostream> #include <string> using namespace std; //global function // static HMODULE g_hModule = NULL; //COMPONENT1 MODULE HANDLE static long g_lComponent = 0; //COMPONENT1 COUNT static long g_lServerLocks = 0; //CFactory COUNT //Friendly Name const char g_szFriendlyName[] = "Inside COM, Chapter 8 Example 1, Component 1"; //Version-independent ProgID const char g_szVerIndProgID[] = "InsideCOM.chap08.ex1.cmpnt1"; //ProgID const char g_szProgID[] = "InsideCOM.chap08.ex1.cmpnt1.1"; //trace function void trace(string msg) { cout<<msg<<endl; } //////////////////////////////////////////// //class CA // class CA : public IX, public IY { public: virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv); virtual ULONG __stdcall AddRef(); virtual ULONG __stdcall Release(); virtual void __stdcall Fx() {cout<<"CA::Fx"<<endl;} virtual void __stdcall Fy(); CA(); ~CA(); HRESULT __stdcall Init(); private: //pointer to the contained components's IY interface IY *m_pIy; long m_cRef; }; CA::CA():m_cRef(1) { InterlockedIncrement(&g_lComponent); m_pIy = NULL; } CA::~CA() { trace("component1 destroy self"); InterlockedDecrement(&g_lComponent); if(m_pIy != NULL) { m_pIy->Release(); } } ULONG __stdcall CA::AddRef() { return InterlockedIncrement(&m_cRef); } ULONG __stdcall CA::Release() { if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; } return m_cRef; } HRESULT __stdcall CA::QueryInterface(const IID& iid, void **ppv) { if(iid == IID_IUnknown) { *ppv = static_cast<IX*>(this); } else if(iid == IID_IX) { *ppv = static_cast<IX*>(this); } else if(iid == IID_IY) { *ppv = static_cast<IY*>(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK; } void __stdcall CA::Fy() { m_pIy->Fy(); } HRESULT __stdcall CA::Init() { HRESULT hr = CoCreateInstance(CLSID_Component2, NULL, CLSCTX_INPROC_SERVER, IID_IY, (void**)&m_pIy); if(FAILED(hr)) { trace("couldn't create contained component"); return E_FAIL; } else { return S_OK; } } ///////////////////////////////////////////// //class factory // class CFactory : public IClassFactory { public: //interface iunknown virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv); virtual ULONG __stdcall AddRef(); virtual ULONG __stdcall Release(); //interface iclassfactory virtual HRESULT __stdcall CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv); virtual HRESULT __stdcall LockServer(BOOL bLock); CFactory(); ~CFactory(); private: long m_cRef; }; CFactory::CFactory():m_cRef(1) { } CFactory::~CFactory() { trace("component1 cfactory : destroy self"); } HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void **ppv) { if(iid == IID_IUnknown || iid == IID_IClassFactory) { *ppv = static_cast<IClassFactory*>(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK; } ULONG __stdcall CFactory::AddRef() { return InterlockedIncrement(&m_cRef); } ULONG __stdcall CFactory::Release() { if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; } return m_cRef; } //CreateInstance HRESULT __stdcall CFactory::CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv) { if(pIUnknownOuter != NULL) { trace("no aggregation"); return CLASS_E_NOAGGREGATION; } //Create Compnent1 CA *pA = new CA(); if(pA == NULL) { return E_OUTOFMEMORY; } HRESULT hr = pA->Init(); if(FAILED(hr)) { //Initialize failed.Delete Component pA->Release(); return hr; } //Get Request interface hr = pA->QueryInterface(iid, ppv); //Release IUnknown interface pA->Release(); return hr; } HRESULT __stdcall CFactory::LockServer(BOOL bLock) { if(bLock == TRUE) { InterlockedIncrement(&g_lServerLocks); } else { InterlockedDecrement(&g_lServerLocks); } return S_OK; } //////////////////////////////////////// //export functions // //Get Interface IClassFactory STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv) { if(clsid != CLSID_Component1) return CLASS_E_CLASSNOTAVAILABLE; CFactory *pFactory = new CFactory(); if(pFactory == NULL) { return E_OUTOFMEMORY; } HRESULT hr = pFactory->QueryInterface(iid, ppv); pFactory->Release(); return hr; } STDAPI DllCanUnloadNow() { if(g_lComponent == 0 && g_lServerLocks == 0) return S_OK; else return S_FALSE; } STDAPI DllRegisterServer() { return RegisterServer(g_hModule, CLSID_Component1, g_szFriendlyName, g_szVerIndProgID, g_szProgID); } STDAPI DllUnRegisterServer() { return UnregisterServer(CLSID_Component1, g_szVerIndProgID, g_szProgID); } BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved) { if(dwReason == DLL_PROCESS_ATTACH) { g_hModule = hModule; } return TRUE; }
LIBRARY cmpnt1.dll DESCRIPTION 'Chapter08 Component1' EXPORTS DllGetClassObject @2 private DllCanUnloadNow @3 private DllRegisterServer @4 private DllUnRegisterServer @5 private
iface.h
#include <objbase.h> interface IX:IUnknown { virtual void __stdcall Fx() = 0; }; interface IY:IUnknown { virtual void __stdcall Fy() = 0; }; extern const IID IID_IX; //Interface ID for IX extern const IID IID_IY; //Interface ID for IY extern const CLSID CLSID_Component1; //CLSID for Cmpnt1 extern const CLSID CLSID_Component2; //CLSID for Cmpnt2
#include <objbase.h> // {32bb8320-b41b-11cf-a6bb-0080c7b2d682} extern const IID IID_IX = {0x32bb8320, 0xb41b, 0x11cf, {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ; // {32bb8321-b41b-11cf-a6bb-0080c7b2d682} extern const IID IID_IY = {0x32bb8321, 0xb41b, 0x11cf, {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ; // {0c092c22-882c-11cf-a6bb-0080c7b2d682} extern const CLSID CLSID_Component1 = {0x0c092c22, 0x882c, 0x11cf, {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ; // {0c092c23-882c-11cf-a6bb-0080c7b2d682} extern const CLSID CLSID_Component2 = {0x0c092c23, 0x882c, 0x11cf, {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
运行结果
包容的主要用途
包容的主要用途是通过给已有的接口加上代码以扩展此接口。