对组件的需求:
第一:组件必须动态连接
第二:它们必须隐藏其内部实现细节。
实际上COM是使用了DLL来给组件提供动态链接的能力。
带来的好处:
1.提供了一个所有组件都应遵守的标准
2.允许使用组件的多个不同版本,而且这一点对于用户而言几乎是透明的
3.使得可以按相同的方式来处理类似的组件
4.支持对远程组件的透明链接
COM接口在C++中是用纯抽象基类实现的
一个COM组件可以提供多个接口
一个C++类可以使用多继承实现一个可以提供多个接口的组件。
#include<iostream>
#include<objbase.h>
using namespace std;
void trace1(const char* pMsg)
{
cout << pMsg << endl;
}
__interface IX
{
virtual void __stdcall Fx1() = 0;
virtual void __stdcall Fx2() = 0;
};
__interface IY
{
virtual void __stdcall Fy1() = 0;
virtual void __stdcall Fy2() = 0;
};
class CTest :public IX, public IY
{
public:
virtual void __stdcall Fx1()
{
trace1("this is Fx1 ");
}
virtual void __stdcall Fx2()
{
trace1("this is Fx2 ");
}
virtual void __stdcall Fy1()
{
trace1("this is Fy1 ");
}
virtual void __stdcall Fy2()
{
trace1("this is Fy2 ");
}
};
int main(void)
{
CTest *pTest = new CTest;
IX *pIX = pTest;
pIX->Fx1();
pIX->Fx2();
IY *pIY = pTest;
pIY->Fy1();
pIY->Fy2();
delete pTest;
cin.get();
return 0;
}
运行结果:
一个接口是一个函数集合,一个组件则是一个接口集,而一个系统则是一系列组件的集合。
对于一个支持多个接口的组件,接口函数的名字出现冲突是经常会遇到的。
此种情况下,改变某个发生冲突的函数名称即可,COM对此并不关心。因为COM接口是一个二进制标准;客户同接口的连接并不是通过 其名称或其成员函数的名称完成的,而是通过它在表示它的内存块中的位置完成的。
接口理论:
1)接口的不变性
接口不会发生任何变化。实际上这是COM接口最令人震撼之处。一旦公布了一个接口,那么它将永远保持不变。不对组件进行升级时,一般不会修改已有的接口,而是加入一些新的接口。
2)多态
多态是指的是可以按同一种方式来处理不同的对象。
接口背后:
1)虚拟函数表
__interface IX
{
virtual void __stdcall Fx1() = 0;
virtual void __stdcall Fx2() = 0;
virtual void __stdcall Fx1() = 0;
virtual void __stdcall Fx2() = 0;
};
抽象基类所定义的内存块结构示例:
2)vtbl指针及实例数据
class CA:public IX
{
public:
// Implement interface IX;
virtual void __stdcall Fx1(){cout<<"CA::Fx1"<<endl;}
virtual void __stdcall Fx2(){cout<<m_Fx2<<endl;}
virtual void __stdcall Fx3(){cout<<m_Fx3<<endl;}
virtual void __stdcall Fx4(){cout<<m_Fx4<<endl;}
CA(double d):m_Fx2(d*d),m_Fx3(d*d*d),m_Fx4(d*d*d*d)
{}
double m_Fx2;
double m_Fx3;
double m_Fx4;
};
实例数据将同vtbl一块保存
3)多重实例
int main()
{
CA* pA1= new CA(1.5);
CA* pA2= new CA(2.5);
}
同一类的多个实例将共享vtbl
4)不同的类,相同的vtbl
class CB:public IX
{
public:
// Implement interface IX;
virtual void __stdcall Fx1(){cout<<"CA::Fx1"<<endl;}
virtual void __stdcall Fx2(){cout<<"CA::Fx2"<<endl;}
virtual void __stdcall Fx3(){cout<<"CA::Fx3"<<endl;}
virtual void __stdcall Fx4(){cout<<"CA::Fx4"<<endl;}
};
void foo(IX* pIX)
{
pIX->Fx1();
pIX->Fx2();
}
INT main ()
{
CA* pA = new CA(1.5);
CB* pB = new CB;
IX* pIX = pA;
foo(pIX);
pIX = pB;
foo(pIX);
}
通过 一个共同的抽象基类来一一致的使用两个不同的类。