描述:
在第八章中的一个例子,组件CA实现了接口IX,CB实现了接口IY,CA聚合CB。如下
CA::Init()
{
...
HRESULT hr =
::CoCreateInstance(CLSID_Component2,
pUnknownOuter, // Outer component's IUnknown @N
CLSCTX_INPROC_SERVER,
IID_IUnknown, // IUnknown when aggregating @N
(void**)&m_pUnknownInner) ;
hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ;
//此时m_pUnknownInner应该指向内部组件的非代理未知接口,问题1.内部组件的非代理未知接口,
//并未实现QueryInterface(IID_IY, (void**)&m_pIY),为什么在此可以调用QueryInterface
//(IID_IY, (void**)&m_pIY)。问题2.当调用这个m_pUnknownInner->QueryInterface(IID_IY,
//(void**)&m_pIY) ;后,内部组件将调用转给外部组件的QueryInterface。外部组件是这样实现的
// else if (iid == IID_IY)
// {
// trace("Return inner component's IY interface.") ;
//#if 1
// You can query for the interface.
// return m_pUnknownInner->QueryInterface(iid,ppv) ; //@N
//#else
// Or you can return a cached pointer.
// *ppv = m_pIY ; //@N
//这样外部组件m_pUnknownInner->QueryInterface(iid,ppv),相当于又调用内部组件的
//QueryInterface,这样形循环调用,不就出错了吗,为什么,初学请高手帮忙
...
}
解决方案1:
是这样的:
1.虚函数的调用是基于虚表的,而不是函数名称,举个简单的例子
Class A
{
virtual void PrintA()
{
printf("A::PrintA()\n");
}
}
class B
{
virtual void PrintB()
{
printf("B::PrintB()\n");
}
}
main()
{
A* pA = new A;
B* pB = (B*)pA;
pB->PrintB();
}
com里面的那个m_pUnknownInner用的是同样的方式,委托IUnknown和非委托IUnknown虚表结构完全相同,所以和上面的例子类似,pB->PrintB()输出A::PrintA()
2.同样的道理m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY)
调用的是非委托的QueryInterface,请求IID_IY
1、非代理IUnknown接口和代理IUnknown接口内存布局一致(函数原型和地址顺序一致),可以互相强制转换(必须使用reinterpret转换)。
2、外部组件m_pUnknownInner->QueryInterface(iid,ppv),调用的是内部组件非代理IUnknown接口上的QueryInterface实现,这时调用不会再转发给外部组件的QueryInterface,不会造成循环。