C++基础问题!对指针理解比较深的高手和精通COM的专家请进!(菜鸟勿进)嫌分不够的话可以重开帖子另给!
小弟正在学习COM在历届接口的查询时陷入了万劫不复之地!请高手指点迷津!
下面是我的一个简单模拟与分析,程序很简单!/
/ ComTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include"iostream.h"
enum UUID {IID_IANIMAL=100,IID_ICANJUMP,IID_ICANFLY};
typedef unsigned int UINT;
// Base class for demo
class IAnimal
{
public:
virtual bool QueryInterface(UINT nID,void **ppvObject)=0;
virtual void AddRef()=0;
virtual void Release()=0;
};
class ICanJump:public IAnimal
{
public :
//IAniaml methods
virtual bool QueryInterface(UINT nID,void **ppvObject)=0;
virtual void AddRef()=0;
virtual void Release()=0;
virtual void Jump()=0;
};
class ICanFly:public IAnimal
{
public:
//IAnimal methods
virtual bool QueryInterface(UINT nID,void **ppvObject)=0;
virtual void AddRef()=0;
virtual void Release()=0;
virtual void Fly()=0;
};
class MixAnimal:public ICanJump,public ICanFly
{
private:
long m_lRef;
public:
MixAnimal():m_lRef(0) { }
~MixAnimal() { }
//IAnimal methods
virtual bool QueryInterface(UINT nID,void **ppvObject);
virtual void AddRef();
virtual void Release();
//ICanJump methods
virtual void Jump();
//ICanFly methods
virtual void Fly();
};
bool MixAnimal::QueryInterface(UINT nID,void **ppvObject)
{
switch(nID)
{
case IID_IANIMAL:
*ppvObject=static_cast<ICanJump*>(this);
break;
case IID_ICANJUMP:
*ppvObject=static_cast<ICanJump*>(this);
break;
case IID_ICANFLY:
*ppvObject=static_cast<ICanFly*>(this);
break;
default:
*ppvObject=NULL;
return false;
break;
}
reinterpret_cast<IAnimal*>(*ppvObject)->AddRef();
return true;
}
void MixAnimal::AddRef()
{
m_lRef++;
}
void MixAnimal::Release()
{
m_lRef--;
if(m_lRef==0)
delete this;
}
void MixAnimal::Jump()
{
cout<<"Hi, I can jump very high! !"<<endl;
}
void MixAnimal::Fly()
{
cout<<"Hi,I can fly very high!"<<endl;
}
int main(int argc, char* argv[])
{
IAnimal *pIAnimal=NULL;
ICanJump *pICanJump=NULL;
ICanFly *pICanFly=NULL;
MixAnimal *pMixAnimal=new MixAnimal;
pMixAnimal->QueryInterface(IID_IANIMAL,reinterpret_cast<void**>(&pIAnimal));
//Output the value of pIAnimal pointer
cout<<pIAnimal<<endl;
//First search the Interface of ICanJump
if(pIAnimal!=NULL)
{
if(pIAnimal->QueryInterface(IID_ICANJUMP,reinterpret_cast<void**>(&pICanJump))&&pICanJump!=NULL)
{
//Output the value of pICanIump pointer
cout<<pICanJump<<endl;
pICanJump->Jump();
pICanJump->Release();
}
}
//Secondly search the interface of ICanFly
if(pIAnimal->QueryInterface(IID_ICANFLY,reinterpret_cast<void**>(&pICanFly))&&pICanFly!=NULL)
{
//Output the value of pICanFly pointer
cout<<pICanFly<<endl;
pICanFly->Fly();
pICanFly->Release();
pICanFly->QueryInterface(IID_ICANJUMP,reinterpret_cast<void**>(&pICanJump));
//Output the value of pICanJump pointer
cout<<pICanJump<<endl;
pICanJump->Release();
}
pMixAnimal->Release();
return 0;
}
下面是我的一个输出结果:
//Output the value of pIAnimal pointer
0x004102E0
Hi, I can jump very high!
0x004102E4
Hi,I can fly very high!
0x004102E0
//个人分析:
由于用到了虚函数使得类MixAniaml的内存分布可能为:
已经省略掉了该类所关联的type_info object.
----------->pfnQueryInterface
| pfnAddRef
| pfnRelease
| pfnJump
this -----> vptrCanJump--
vptrCanFly--------------->pfnQueryInterface
m_lRef pfnAddRef
pfnRelease
pfnFly
显然输出结果:(不同的机器的输出结果可能不同!)
0x004102E0 应该为指针vptrCanJump的值,而0x004102E4因该为指针vptrCanfly的值
我的问题出现在函数bool MixAnimal::QueryInterface(UINT nID,void **ppvObject)上面
该函数在实现时使用了强制类型转换,
.......
switch(nID)
{
case IID_IANIMAL:
*ppvObject=static_cast<ICanJump*>(this);
break;
case IID_ICANJUMP:
*ppvObject=static_cast<ICanJump*>(this);
break;
case IID_ICANFLY:
*ppvObject=static_cast<ICanFly*>(this);
break;
}
........
我想知道的是在我的程序中用四次改函数的调用,在每一调用时函数里面的this指针是怎么传递进去的?
我的理解是该函数应该被编译器解释成下面的样子:
bool MixAnimal::QueryInterface(MixAnimal *this,UINT nID,void **ppvObject)
而函数调用:
pMixAnimal->QueryInterface(IID_IANIMAL,reinterpret_cast<void**>(&pIAnimal));
应该被转化为:
(*pMixAnimal-vptrCanJump[1])QueryInterface(pMixAnimal,IID_IANIMAL,reinterpret_cast<void**>(&pIAnimal));
也就是说将最左边的类指针作为this指针传递进去!
其他的函数调用也是这样,但是这样就出现了一个奇怪的问题:我们可以通过类型强制转化从一个整体得到局部
(这很正常),但是我们却不能够从一个局部通过类型转换得到整体!但是事实上我们却做到了!why?
我的意思是:
我在第一次调用时将pMixAniaml作为this指针,通过类型转化可以很容易的得到pAnimal,因为pAnimal可以看成
this所指的对象的一个局部(在该函数的具体的实现中可以看出来!)
我在第二次用pAnimal调用函数时,也应该很容易的得到pCanJump的值,因为在我的实现中他们两者实际上指向同一块地址。
我在第三次用pCanJump调用函数时,也因该正确地得到pCanFly的值,因为这还是由整体得到局部。
强制类型转换的结果使得pCanJump和pCanFly的值不相等!
但是在第四次由pCanFly调用函数时,却不应该正确地得到pCanJump的值,因为这可以看成有一个局部获得整体或者有一个局部获得另一个局部!
真是匪夷所思!
Who Can help me?