1、面向对象系统的三个最基本的特性
封装性、多态性、重用性。
2、COM特性的概述
COM对象的封装特性是很彻底的,所有的对象状态信息必须通过接口才能访问;而COM的多态性完全通过接口体现出来,而且,COM分别在三个层次上体现了多态性:接口成员函数、单个接口、一组接口(对象类别即 implemented category)。而COM的重用性相对复杂。
3、重用性
所谓重用性是指,当一个程序单元能够对其他的程序单元提供功能服务时,尽可能地重用原先程序单元的代码,既可以在源代码一级重用,也可以在可执行代码一级重用。
C++语言的重用性位于源代码一级,一个类可以继承于另一个类,从而把父类的功能重用。但对于COM组件则情形有所不同,因为COM是建立在二进制代码基础上的标准,所以其重用性也必然建立于二进制代码一级。
COM重用性是指一个COM对象如何重用已有的COM对象的功能,而不是重复实现老的功能服务。按照COM的标准,实现这种重用性有两条途径:包容和聚合。
4、包容和聚合
对象B调用对象A的相应成员函数实现ISomeInterface接口。因此,对象B的ISomeInterface接口提供的功能可以超过对象A的接口功能,返回结果也可以不一致。甚至,对象B的接口与对象A的接口不一定相同。一般来说,对象A的生存期包含在对象B的生存期之内。
在聚合模型中,被聚合的对象A虽然直接向对象B的客户程序提供功能服务,但它的生存期仍受对象B控制,而且其他的一些行为也受对象B的控制,包括内部状态初始化、获取数据等等。
为了使聚合能够顺利实现,对象A必须能够适应在被聚合的情况下进行特殊的处理,尤其是接口的QueryInterface成员函数,在被聚合情况下,当客户请求它所不支持的接口或者IUknown接口时,它必须把控制交给外部对象,由外部对象决定客户程序的请求结果。
聚合涉及到聚合对象和被聚合对象双方的协作,并不是每个对象都能够支持聚合特性,但聚合体现了组件软件真正意义上的重用。而包容的重用性完全建立在客户/服务器模型相对性的基础上,实际上也就是客户程序和组件程序的嵌套关系。这是包容和聚合本质的不同。
5、委托IUnknown和非委托IUnknown
对象创建函数CoCreateInstance的第二个参数pUnknownOuter用于解决聚合中IUnknown接口的问题。当其为NULL时表示正常使用,不为NULL时被聚合使用。内部对象实现两个IUnknown 分别用于这两种情况:委托IUnknown和非委托IUnknown(delegating unknown和nondelgating unknown)。
按照通常使用方式实现的IUnknown为非委托IUnknown,而委托IUnknown在不同的情况下有不同的行为:当对象被正常使用时,委托 IUnknown把调用传递给对象的非委托IUnknown;当对象被聚合使用时,委托IUnknown把调用传递到外部对象的IUnknown接口,即对象被创建时传递进来的pUnkownOuter参数,并且,这时外部对象通过非委托IUnknown对内部对象进行控制。委托IUnknown本身不进行任何操作。
因为C++类不支持同时实现两个IUnknown,所以委托IUnknown和非委托IUnknown不能都使用IUnknown类,但我们可以定义一个新的类。因为COM不是通过类名来识别接口,而是通过vtable来调用接口成员函数。
6、COM接口调用的进程透明性
客户程序创建COM对象具有进程透明特性,不管是进程内组件还是进程外组件,客户程序可以使用一致的方法创建COM对象。对于进程内组件,无论是创建过程,还是客户程序对接口函数的调用过程,都可以按照一般的同一进程内部函数调用的过程来理解组件和客户之间的交互操作;但对于进程外组件,实际的情形要复杂得多,因为组件程序户程序拥有不同的进程空间,所以,它们之间所有的交互过程都涉及到进程之间的通信过程。然而,COM客户程序创建进程外组件程序成功后,它就得到了组件对象的一个接口指针,通过该指针间接调用组件对象的成员函数,如同调用本进程内的函数一样,这正是COM所期望达到的透明效果。