COM组件聚合中虚函数研究

最近阅读《COM技术内幕》这本书,在讲到组件的聚合时候,看了几遍一直没看明白,最后在网上看到了这篇文章才发现原来是虚函数表在做宗,感慨C++学的不好啊!

 

后来发觉是因为指针的转换造成的.如下面的代码,而且你要保证你的INondelegationUnknown接口函数顺序和IUnknown一致.

仔细阅读下列代码,

class CA : public IA,public INondelegationUnknown , public IB

{

...

};

IA,IB接口都派生于IUnknown

HRESULT CA::NondelegationQueryInterface(const GUID & iid, void ** ppv)
{
*ppv = NULL;
if(iid == IID_IA)
{
   *ppv = (IA*)this;//类型的转换
   ((IA*)*ppv)->AddRef();//使用委托函数,如果被聚合,使外部计数,否则使内部计数
   return S_OK;
}

else if(iid == IID_IB)
{
   *ppv = (IB*)this;
   ((IB*)*ppv)->AddRef();//使用委托函数,如果被聚合,使外部计数,否则使内部计数

   return S_OK;
}
else if(iid == IID_IUnknown)
{
   *ppv = (INondelegationUnknown*)this;//类型的转换(这里的类型转换很重要)
   ((IUnknown*)*ppv)->AddRef();//实际上调用了NondelegationAddRef,可以想像一下指针在内存的位置,可直接替换为NondelegationAddRef,这里是唯一一后门可以得到非代理IUnknow指针的地方.

   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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在MySQL聚合函数是用于对数据集进行汇总计算的函数。常见的MySQL聚合函数包括: - AVG:计算某列的平均值 - SUM:计算某列的总和 - COUNT:计算某列的行数 - MAX:返回某列的最大值 - MIN:返回某列的最小值 - GROUP_CONCAT:将某列的值连接成一个字符串 这些聚合函数可以在SELECT语句的SELECT子句使用,通常与GROUP BY子句一起使用,用于按照指定的列进行分组,并计算每个组的聚合结果。聚合函数还可以与HAVING子句一起使用,用于对聚合结果进行筛选。 例如,以下是一些使用聚合函数的MySQL查询示例: 1. 计算某列的平均值: ``` SELECT AVG(column_name) FROM table_name; ``` 2. 计算某列的总和: ``` SELECT SUM(column_name) FROM table_name; ``` 3. 计算某列的行数: ``` SELECT COUNT(column_name) FROM table_name; ``` 4. 返回某列的最大值: ``` SELECT MAX(column_name) FROM table_name; ``` 5. 返回某列的最小值: ``` SELECT MIN(column_name) FROM table_name; ``` 6. 将某列的值连接成一个字符串: ``` SELECT GROUP_CONCAT(column_name) FROM table_name; ``` 需要注意的是,聚合函数只能用于SELECT语句,不能用于WHERE、ORDER BY和HAVING子句。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【MySQL】聚合函数](https://blog.csdn.net/Decade0712/article/details/129759317)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值