第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(