关于<>的三个问题

xhncmec 2005-01-11 03:02:12
在看<<com原理与应用>>,有一段话不是很理解,请高手赐教!!!

一、
一个组件类CMy实现了两个接口IA、IB,它们都继承自接口IUnknown,在查询IUnknown接口时,我们先把this转换成IA 或者 IB 指针,再转换成IUnknown,但我们必须保证每次查到的IUnknown接口完全一致。
那么我就有点不明白了,为什么会返回相同的指针?我按书中的要求,在CMy::QueryInterface中
用 *ppv = (IUnknown *)(IA *)this
或 *ppv = (IUnknown *)(IB *)this ,它们的*ppv不一样,也就是说,获得的IUnknown接口不一致,该如何解释???

二、
类CMy实现了两个接口IA、IB,能不能说同时也实现了接口IUnknow?

三、
为什么每次用VC查看接口IA、IB时,只能看到接口IUnknow中的那三个函数?却看不到其它接口的函数?如何解释?
...全文
284 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
同桌老王 2005-01-14
  • 打赏
  • 举报
回复
上面帖子的结果:
IA
ppv = 0x3742c8
*ppv = 0x414060
&ppv=0x12ff58
IB
ppv = 0x3742cc
*ppv = 0x414130
&ppv=0x12ff58
Press any key to continue
同桌老王 2005-01-14
  • 打赏
  • 举报
回复
为你写一个例子:

//

#include "stdafx.h"
#include "IAIB.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;
struct CBase{
virtual void func()=0;
};
class IA:public CBase{
public:
virtual void func()
{
printf("IA\n");
}
};
class IB:public CBase{
public:
virtual void func()
{
printf("IB\n");
}
};
class CAB:public IA,IB{
public:
void query(void **ppv,int id)
{
if(id==0)
{
*ppv = (IA*)this;
}
else if(id==1)
{
*ppv = (IA*)this;
}
else if(id==2)
{
*ppv = (IB*)this;
}
else
{
*ppv = 0;
printf("we have no this interface\n");
}
}
};
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;

// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
CAB *p = new CAB;
CBase *ppv=0;
p->query((void**)&ppv,0);
ppv->func();
printf("ppv = 0x%x\n",ppv);
printf("*ppv = 0x%x\n",*ppv);
printf("&ppv=0x%x\n",&ppv);

p->query((void**)&ppv,2);
ppv->func();
printf("ppv = 0x%x\n",ppv);
printf("*ppv = 0x%x\n",*ppv);
printf("&ppv=0x%x\n",&ppv);
delete p;
}

return nRetCode;
}


xenter 2005-01-14
  • 打赏
  • 举报
回复
To: kevin_wang(砸锅卖铁)

你的代码有问题:
成员函数原型void query(void **ppv,int id)中的ppv与p->query((void**)&ppv,0);中的ppv不是同一个变量,前面那个ppv是指针的指针,后面那个ppv是指针,你的意思就是把后面那个 &ppv 赋值给前面那个ppv,也就是ppv=&ppv,不建议此种写法,容易混混淆视听。

你的代码结果:
ppv 就是接口指针
*ppv 就是接口对象
&ppv 就是接口指针的指针,没有意义

COM规范中所说的保证每次查到的IUnknown接口完全一致,在main()中说的就是ppv
在成员函数void query(void **ppv,int id)中,说的就是*ppv
thunderclap 2005-01-13
  • 打赏
  • 举报
回复
收到,谢谢!
xhncmec 2005-01-13
  • 打赏
  • 举报
回复
to:thunderclap(不会游泳的鱼)

我觉得你最后回复的那两个贴比较合理!
xhncmec 2005-01-13
  • 打赏
  • 举报
回复
to:thunderclap(不会游泳的鱼)

我觉得你最后回复的那个贴比较合理!
thunderclap 2005-01-13
  • 打赏
  • 举报
回复
其实你在实现QueryInterface是只要实现那5个规则就好了。
thunderclap 2005-01-13
  • 打赏
  • 举报
回复
一般在将this指针值赋给某个void指针时,应先将其转换成合适的类型。一个有趣的例子是返回
IUnknown指针的情形。某些程序员可能会用:
*ppv = static_cast<IUnknown*>(this);
但是将this指针转换成IUnknown*是不明确的。这是由于IX和IY都是从
IUnknown继承得到的。
因此在这种情况下,返回值应该是
*ppv = static_cast<IUnknown*>(static_cast<IX*>(this)) 或者是
*ppv = static_cast<IUnknown*>(static_cast<IY*>(this))。
只不过在在上面,选择哪一个是无关紧要的,因为它们使用的都是同一实现。
但是在代码中要保持一致,因这两个指针实际上是不一样的,并且COM
要求对IUnknown接口返回相同的指针。
上面的话是《COM技术内幕——微软组件对象模型》书中的一段。
hithyy 2005-01-13
  • 打赏
  • 举报
回复
有收获
xhncmec 2005-01-12
  • 打赏
  • 举报
回复
你要是通过QueryInterface来查询接口IUnknown,肯定是相等的

因为
if(iid == IID_IUnknown)
{
*ppv = (IA*)this;
((IA*)(*ppv))->AddRef();
}
可是,你要是变成这样

if(iid == IID_IUnknown)
{
*ppv = (IB*)this;
((IB*)(*ppv))->AddRef();
}

第二次查询的接口IUnknown 的值就不一样了
xhncmec 2005-01-12
  • 打赏
  • 举报
回复
to:thunderclap(不会游泳的鱼)

能把你的代码发给我吗?hncmec@yahoo.com.cn
我按你的要求试了一下,还是不一致

to:IFindit(寻找其中的乐趣)
我知道用QuerInterface应该就是相等的,但为什么当iid == IID_IUnknown时
*ppv = (IA*)this; 而不是 *ppv = (IB*)this; ?
IFindit 2005-01-12
  • 打赏
  • 举报
回复
*ppv = (IUnknown *)(IA *)this
*ppv = (IUnknown *)(IB *)this
这样是强制转换, 两个this值不一样。 用QuerInterface应该就是相等的了, 其实Delhpi中的as也是调用了QuerInterface子函数!
thunderclap 2005-01-12
  • 打赏
  • 举报
回复
这个由虚继承的运行时的多态性决定的。
thunderclap 2005-01-12
  • 打赏
  • 举报
回复
真的是相等的,你不用分两次做。你可以这样来验证。
自己分别定义两个IID,如:IID_IUnknown1, IID_IUnknown2
象IX, IY一样的定义
然后修改QueryInterface为如下:
HRESULT CMy::QuerInterface(const IID& iid, void**ppv)
{
if(iid == IID_IUnknown)
{
*ppv = (IA*)this;//注意这里
((IA*)(*ppv))->AddRef();
}
if(iid == IID_IUnknown1)
{
*ppv = (IUnknown *)((IA *)this));
((IA*)(*ppv))->AddRef();
}
if(iid == IID_IUnknown2)
{
*ppv = (IUnknown *)((IB *)this));
((IA*)(*ppv))->AddRef();
}
else if(iid == IID_IA)
{
*ppv = (IA*)this;
((IA*)(*ppv))->AddRef();
else if(iid == IID_IB)
{
*ppv = (IB*)this;
((IB*)(*ppv))->AddRef();
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
return S_OK;
}

//客户
IUnknown * ppv1;
IUnknown * ppv2;
this->QueryInterface(IID_IUnknown1, &ppv1);//ppv1是通过*ppv = (IUnknown *)((IA *)this));
this->QueryInterface(IID_IUnknown2, &ppv2);//ppv2是通过*ppv = (IUnknown *)((IB *)this));
你这样做两个肯定一样。
ilovevc 2005-01-11
  • 打赏
  • 举报
回复
你要去通过QueryInterface(IID_IUnknown, &ppv)获得的接口才会相等啊。

*ppv = (IA *)this;
*ppv = (IB *)this;

这样实际上就是static_cast转换。一个指向IA接口起始位置,一个IB起始位置,相等才怪。

试试这样:
void * ppv1, *ppv2;
this->QueryInterface(IID_IUnknown, &ppv1);
this->QueryInterface(IID_IUnknown, &ppv2);

assert( ppv1 == ppv2);

或者先分别得到IA和IB的指针,
this->QueryInterface(IID_IA, &pa);
this->QueryInterface(IID_IB, &pb);

然后再通过不同的接口指针查IUnknown,
pa->QueryInterface(IID_IUnknown, &ppv1);
pb->QueryInterface(IID_IUnknown, &ppv2);
assert( ppv1 == ppv2);
xhncmec 2005-01-11
  • 打赏
  • 举报
回复
to: canji

关于第3个问题,
*ppv = (IA *)this 我查看了this指针,里面只有接口IA、IB,但看它们的成员函数,只看到接口IUnknown的那三个函数。
xhncmec 2005-01-11
  • 打赏
  • 举报
回复
To:jiangsheng(蒋晟.MSMVP2004Jan)

1、转换成不同类型,*ppv 的值不一样,不信你可以试一下便知
*ppv = (IUnknown *)(IA *)this
*ppv = (IUnknown *)(IB *)this
我用的是<<COM原理与应用>>中源码,实际上你也可以写一段代码试一下。

2、是不是实现了addref、release、queryinterface等函数后才算是实现了接口IUnknown

3、在VC中设中断查看this->IA->底下只有接口IUnknow->_vfptr->底下只有那三个函数,却看不到接口IA的函数,为什么???
XXandOO 2005-01-11
  • 打赏
  • 举报
回复
1是COM规范,目的是提供一个有效的方法来判断两个接口指针是否属于同一个COM对象实例,但其他接口指针不具此性质,甚至可以两次查询同一个接口而返回不同的值,比如teatoff接口。
Magnus 2005-01-11
  • 打赏
  • 举报
回复
关于第一个问题,
牵扯到虚拟继承的问题,
虚拟继承的时候,无论自己的父类在继承树中出现几次,
编译器都使他实际只出现一次,

所以会返回相同的指针。

另外两个问题不是问题
canji 2005-01-11
  • 打赏
  • 举报
回复
1 所谓“必须保证每次查到的IUnknown接口完全一致”指的是 *ppv的值(即返回值)相同。
2 对,这就是所谓的“菱形继承”了。
3 你的意思是说只有IUnknow的三个函数可以不查询直接调用,别的函数必须查询是吧?这是因为你是把*ppv作为 IUnknow* 来使用的。如果你直到*ppv的确切类型,直接调用它也是可以的。例如:
(IA*)*ppv->FA();

加载更多回复(6)

3,245

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧