第四章的例程sample\\ch4中有一段:
HRESULT CA::NondelegationQueryInterface(const IID& iid, void **ppv)
{
if ( iid == IID_IUnknown )
{
*ppv = (INondelegatingUnknown *) this ;
((IUnknown *)(*ppv))->AddRef() ;
} else if ( iid == IID_SomeInterface ) 
{
*ppv = (ISomeInterface *) this ;
((ISomeInterface *)(*ppv))->AddRef() ;

else
{
*ppv = NULL;
return E_NOINTERFACE ;
}
return S_OK;
}
对上述代码中((IUnknown *)(*ppv))->AddRef() 感到迷惑不解:
1.为什么要转化为指针(IUnknown *),明明INondelegatingUnknown不是继承自IUnknown,
2.经过跟踪,实际上系统并不是调用AddRef,而是调用NondelegatingAddRef去了,怎么会跑到那里去?

解决方案 »

  1.   

    3.可不可以将这句改成
              ((INondelegatingUnknown *)(*ppv))->NondelegatingAddRef() ;
      

  2.   

    我对COM不太熟, 不过这个问题我也研究了好久.首先, CA是从IUnknown和INondelegatingUnknown, 对吧?
    有没有发现,INondelegatingUnknown与IUnknown有什么相同与不同呢?
    相同都有那三个相同功能的函数, 不同是两个接口的这三个函数只是名字不一样, 对吧?
    还有一个相同的地方可能你没有注意, 就是三个函数在类体里定义的先看次序, 有没有发现是相同的吗? 对是相同的而且还是要必须相同. 因为函数的调用实际是汇编call 函数地址. 对于一个类里定义的函数实际是一个一个的地址偏移. 如果地址偏移是一样而且参数个数与排列都一样,名字叫啥又有什么区别呢? 
    ((IUnknown *)(*ppv))->AddRef() ;只是把编译器给骗了,好让它通过. 不过因为偏移与参数都是一样(没参数) 所以就会有那样的结果罗. 你可以把INondelegatingUnknown的AddRef与Release位置换一下看看是不是就调用了Release()
    实际上, 从功能要求来看把下面代码改为
    *ppv = (INondelegatingUnknown *) this ;
    ((IUnknown *)(*ppv))->AddRef() ;
         *ppv = (INondelegatingUnknown *) this;
         ((INondelegatingUnknown *) this)->NondelegatingAddRef();
    这样谁都清楚, 谁也不骗谁了.
        那MS 的什么DON BOX 真够绝.