第二章 接口

类别:VC语言 点击:0 评论:0 推荐:
再谈接口与实现

用户可以选择任何一个C++编译器,但最终他们必须要使用一个C++(而不是其它语言)的编译器.

COM提供了这样一种语言,它只用了大家都很熟悉的C语言的语法,同时加入了某些用于消除C语言中二义性的能力,称接口定义语言

IDL (Interface Definition Language)

COM IDL 以OSF的DCE RPC IDL 为基础加入与COM相关的扩展(继承,多态)

MIDL.EXE是IDL编译器,

产生C/C++兼容的头文件

产生一个二进制文件,称类型库文件

方法与效果

每个COM方法返回一个HRESULT值,

分成三部分:严重程度位,操作码和信息码

如HRESULT指示一个不正常的结果,则Java虚拟机会抛出异常,

而C++则要手工检查HRESULT.

接口与IDL

IDL用interface 关键字定义接口

定义:接口名,基接口名,接口体,接口属性

每个COM接口都至少有两个属性:一个是[object] 表明是COM 而不是DCE风格的接口; 一个是接口的实际名字[uuid]

GUID是一个128位的大数,可以保证在时间和空间范围内都是唯一的,标准文本格式用于[uuid]

  IUnknown

方法: QueryInterface(), AddRef(), Release();

IUnknown是所有接口的根源

COM禁止多重接口继承,但实现可以暴露多个接口

 

资源管理与IUnknown

COM的引用计数规则:

1.当一个非空接口指针从一个内存位置拷贝到另一个内存位置时,调用AddRef();

2. 对已经包含非空接口指针的内存位置而言,在复写内存之前要调用Release();

3.如果可能,多余的AddRef()和Release()可以被优化掉;

调用规则:

AddRef()

A1 当把一个非空接口指针写到局部变量时;

A2 当被调用方把一个非空接口指针写到方法或者函数的[out]或[in, out]参数中时

A3 当被调用方返回一个非空接口指针作为函数的实际结果时

A4 把一个非空接口指针写到对象的一个数据成员时

Release ()

R1 改写一个非空局部变量或者数据成员之前

R2 离开非空局部变量的作用域之前

R3 被调用方要改写方法或者函数的[in, out]参数,且参数初始值非空时

R4 改写对象非空数据成员之前

R5 离开对象析构函数之前

特殊规则

S1 调用方把一个非空接口指针通过[in]参数传给函数时,不必调用A或R

类型强制转换与IUnknown

HRESULT QueryInterface([in] REFIID riid, [out] void **ppv);

若对象不支持所请求的接口类型,那么ppv置为null, 返回E_NOINTERFACE

若支持,则改写指针, 返回S_OK,调用AddRef();

AddRef 和Release不是针对整个对象的操作,而是针对接口指针的操作

Void**导致的类型不安全性漏洞,可用宏IID_PPV_ARG解决

实现IUnknown

AddRef()和Release()

类定义中的析构函数为protected,保证对象总是在堆上创建,delete this总是正确的.

但有时我们希望对象不是在堆中分配,这时引用计数可进行优化,返回一个参考值

QueryInterface()

当一个请求被多个接口支持时,类型转换操作必须明确选择一个更为精确的基类

使用COM接口指针

因为COM对应的C++语言映射没有提供runtime layer, C++程序员必须显示地使用IUnknown的方法,但这样代码效率更高

对Java 和VB而言, IUnknown 的细节隐藏在虚拟机之后.

智能指针可以使在C++中使用COM接口指针的操作简化.

但它也带来许多问题.

优化QueryInterface

每个COM兼容的类都提供了一个表格,通过固定的偏移或其它技术,把该类所支持的IID映射到对象的某个地方.

(类似于MFC中的消息映射宏)

数据类型

OLECHAR到TCHAR的转换

BSTR:字符串类型

IDL和COM也支持联合(Union),为保证解释不存在二义性,要提供全个鉴别器

COM提供了一个通用的,通过鉴别的联合给VB使用,称VARIANT

COM的接口也可以作为参数进行传递: 静态或动态

IDL属性与COM属性

指明一个对象具有某些公开可见的属性,并可通过COM接口来访问或修改这些属性天有些情况下是很有用的.

COM IDL允许接口的方法上加上一些注释,反映该方法可用于读写对象的某个属性

异常

COM的异常API: 抛出SetErrorInfo() 捕捉异常GetErrorInfo();

COM异常对象必须支持IErrorInfo接口

抛出异常的对象必须实现IsupportErrorInfo接口,以便确定哪个接口支持异常

COM要求禁止"纯C++异常"传播到方法的边界之外

本文地址:http://com.8s8s.com/it/it690.htm