INondelegationUnknown接口

原文地址:http://hi.baidu.com/sanvy4116/blog/item/0a4159d08e118b88a0ec9ce4.html

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; 
}


  图中,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 AggregateClass::QueryInterface(const GUID& iid, void **ppv)
{
  if (iid == IID_IA || iid == IID_IB)
    return pInner->QueryInterface(); // 因为指针指向非委托函数,所以相当于调用非委托函数。
  else
    // 返回自己实现的接口,包括IUnknown
}

  AggregateClass为外部组件,pInner为内部组件(CA)返回的IUnknown指针,实际指向INondelegationUnknown函数。
  当客户需要内部组件实现的接口时,客户并不清楚这个接口是在哪里实现的,它会使用从外部组件获取的指针来查询,当这个接口(肯定不会是IUnknown,外部组件应该处理)是由内部实现的时候,外部组件会直接调用组件的INondelegation::QueryInterface函数,此时提供给用户的接口指针必须满足这样的要求:
  1.该指针指向的IUnknown应该是代理的。也就是外部组件的,这就是为什么NondelegationQueryInterface里,除了申请IUnknown接口指针时是非委托的IUnknown,其它的接口都是委托的,实际上委托是因为申请这些接口的肯定是客户端,申请IUnknown接口的肯定是外部组件。
  2.为什么“申请IUnknown接口的肯定是外部组件”,因为聚合时,外部组件自己有IUnknown接口,它不会在客户申请IUnknown时将请求发给聚合使用的组件。它申请内部组件的IUnknow接口只有一个作用,就是聚合使用。(前面已经提到)
  3.通过非代理IUnknown函数,可以控制内部组件生存周期。
  另外,一个组件要提供聚合能力,必须实现两套IUnknown虚函数,一套用于内部的非代理IUnknown函数,一套用于转发请求的委托IUnknown。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值