COM组件聚合中虚函数研究
最近阅读《COM技术内幕》这本书,在讲到组件的聚合时候,看了几遍一直没看明白,最后在网上看到了这篇文章才发现原来是虚函数表在做宗,感慨C++学的不好啊! 后来发觉是因为指针的转换造成的.如下面的代码,而且你要保证你的INondelegationUnknown接口函数顺序和IUnknown一致. 仔细阅读下列代码, class CA : public IA,public INondelegationUnknown,public IB { ... }; IA,IB接口都派生于IUnknown HRESULT CA::NondelegationQueryInterface(const GUID & iid,void ** ppv) else if(iid == IID_IB) return S_OK; return E_NOINTERFACE; http://hi.csdn.net/space-139750-do-album-picid-629060.html 图中,pCA是CA类型的指针,CA,IA和IUnknown类型的同一个实例的指针值是一样的(0x0044213c),都是这个实例在内存位置 的最开始处,但INondelegationUnknown就在后面了,IB在更后面,当将指针类型转换为INondelegationUnknown这 种类型时,再以指针按IUnknown的类型调用AddRef函数,可以想见实际上调用了NondelegationAddRef ,如果你的INondelegationUnknown接口函数顺序和IUnknown不一致,此时就会出错. 在聚合使用时,因为在组件被创建的时候,其外部接口指针(pOut)就不空了,然后调用它的 IUnknow函数时,委托IUnknow函数总是会派发到其pOut所指向的函数,如何调用组件本身的函数呢,只能通过IID_IUnknown获得非 代理的函数调用.(上面的例子IB类型的IUnknown函数实际是都是一段跳转到前一个IA的IUnknown函数的Thunk代码,它是真正的实现位 置,CA对IA,IB的IUnknown的实现只有一份).
要聚合使用 组 件 , 外部 组 件 应该仅 当客户需要 内部 组 件提供的接口 时 才把 调 用 转 向内部 组 件的 INondelegation :: QueryInterface, 而且外部 组 件不 应该 向内部 组 件申 请 它要聚合使用的接口 供内部使用 ( 包容的 实现 方法 ). 下面是一个聚合使用的例子 : Void A ggregate Class:: QueryInterface ( const GUID & iid,void ** ppv ) { If(iid == IID_IA || iid == IID_IB) return pInner-> QueryInterface ();// 因为指针是指向非委托函数的 , 所以相当于调用非委托函数 . Else { // 返回自己实现的接口 , 包括 IUnknown } } A ggregate Class为外部组件, pInner 为内部组件(CA)返回的 IUnknown 指针 , 实际指向 INondelegationUnknown 函数 . 当客 户 需要内部 组 件 实现 的接口 时 , 客 户 并不清楚 这 个接口是在哪里 实现 的 , 它会使用从外部 组 件 获 取的指 针 来 查询 , 当 这 个接口 ( 肯定不会是 IUnknown, 外部 组 件 应该处 理 ) 是由内部 实现 的 时 候 , 外部 组 件会直接 调 用 组 件的 INondelegation::QueryInterface 函数 , 此 时 提供 给 用 户 的接口指 针 必 须满 足 这样 的要求 : 1.该指针指向的IUnknown应该是代理的.也就是外部组件的.这就是为什么 NondelegationQueryInterface里,除了申请IUnknown接口指针时,是非委托的IUnknown,其它的接口都是委托的,实际上委托是因为申请这些接口的肯定是客户端, 申请IUnknown接口的肯定是外部组件 . 2.为什么"申请IUnknown接口的肯定是外部组件",因为聚合时,外部组件自己有IUnknown接口,它不会在客户申请IUnknown时,将请求发给聚合使用的组件。它申请内部组件的IUnknow接口只有一个作用,就是聚合使用.(前面已经提到) 3.通过非代理IUnknown函数,可以控制内部组件生存周期. 另外,一个组件要提供聚合的能力,也必须实现以下两套IUnknown虚函数,一套用于内部的非代理IUnknown函数,一套用于 转发请 求的委托 IUnknown. FROM:http://hi.baidu.com/sanvy4116/blog/item/0a4159d08e118b88a0ec9ce4.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ruby-on-rails – 如何在Devise注册控制器中添加新动作?
- jz2440平台nandflash驱动分析
- 在哪里可以找到PostGresql 9.2 JDBC 4驱动程序在maven repo
- oracle下创建dblink
- Json.net实现方便的Json转C#(dynamic动态类型)对象
- c# – CryptographicException:填充无效,无法删除,并且vie
- c# – 多行文本框根据文本量自动调整高度
- c# – DetailsView仅在2次点击后才更新和更改,取消不显示re
- Oracle_071_lesson_p10
- ruby-on-rails – rspec给出的错误`Then`在示例中不可用(例