这一章主要介绍QueryInterface函数,我觉得其中最重要的是了解程序的整体结构.即包含哪几个文件,每个文件有哪些类,每个类是做什么的.书中有个完整的例子.代码如下:
#include
<
iostream.h
>
#include
<
objbase.h
>
//
To Compile use:cl IUnknown.cpp UUID.lib
void
trace(
const
char
*
msg)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
cout<<msg<<endl;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Interfaces
interface
IX:IUnknown
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
virtual void _stdcall Fx() = 0;
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
interface
IY:IUnknown
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
virtual void _stdcall Fy() = 0;
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
interface
IZ:IUnknown
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
virtual void _stdcall Fz() = 0;
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
extern
const
IID IID_IX;
extern
const
IID IID_IY;
extern
const
IID IID_IZ;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Component
class
CA:
public
IX,
public
IY
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
virtual HRESULT _stdcall QueryInterface(const IID& iid, void** ppv);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
virtual ULONG _stdcall AddRef()...{return 0;}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
virtual ULONG _stdcall Release()...{return 0;}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
//interfac IX implementation
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
virtual void _stdcall Fx()...{cout<<"Fx()"<<endl;}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
//interfac IY implementation
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
virtual void _stdcall Fy()...{cout<<"Fy()"<<endl;}
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
HRESULT _stdcall CA::QueryInterface(
const
IID
&
iid,
void
**
ppv)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
if (iid == IID_IUnknown)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("QuerInterface:Return pointer to IUnknown");
*ppv = static_cast<IX*>(this);
}
else if(iid == IID_IX)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("QueryInterface: Return pointer to IX.");
*ppv = static_cast<IX*>(this);
}
else if (iid == IID_IY)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("QueryInterface: Return pointer to IY.");
*ppv = static_cast<IY*>(this);
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("QueryInterface: Interface not supported.");
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Creation function
IUnknown
*
CreateInstance()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
IUnknown* pI = static_cast<IX*>(new CA);
pI->AddRef();
return pI;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
IIDs
static
const
IID IID_IX
=
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
0x32bb8320,0xb41b,0x11cf,...{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
static
const
IID IID_IY
=
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
0x32bb8321,0xb41b,0x11cf,...{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
static
const
IID IID_IZ
=
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
0x32bb8322,0xb41b,0x11cf,...{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
int
main()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
HRESULT hr;
trace("Client: Get an IUnknown pointer.");
IUnknown* pIUnknown = CreateInstance();
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Get Interface IX.");
IX *pIX = NULL;
hr = pIUnknown->QueryInterface(IID_IX,(void**)&pIX);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Succeeded getting IX.");
pIX->Fx();
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Get Interface IY.");
IY *pIY = NULL;
hr = pIUnknown->QueryInterface(IID_IY,(void**)&pIY);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Succeeded getting IY.");
pIY->Fy();
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Ask for an unsuppoered interface.");
IZ *pIZ = NULL;
hr = pIUnknown->QueryInterface(IID_IZ,(void**)&pIZ);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Succeeded getting IZ.");
pIZ->Fz();
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Could not get interface IZ.");
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Get interface IY from interface IX.");
IY* pIYfromIX = NULL;
hr = pIX->QueryInterface(IID_IY,(void**)&pIYfromIX);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Succeeded getting IY.");
pIYfromIX->Fy();
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Get interface IUnknown from interface IY.");
IUnknown* pIUnknownfromIY = NULL;
hr = pIY->QueryInterface(IID_IUnknown,(void**)&pIUnknownfromIY);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
cout<<"Are the IUnknown pointers equal? ";
if (pIUnknownfromIY == pIUnknown)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
cout<<"Yes,pIunknownfromIY == pIunknown."<<endl;
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
cout<<"No,pIUnknownfromIY != pIunknown."<<endl;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
//Delete the component.
delete pIUnknown;
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/*输出结果
Client: Get an IUnknown pointer.
Client: Get Interface IX.
QueryInterface: Return pointer to IX.
Client: Succeeded getting IX.
Fx()
Client: Get Interface IY.
QueryInterface: Return pointer to IY.
Client: Succeeded getting IY.
Fy()
Client: Ask for an unsuppoered interface.
QueryInterface: Interface not supported.
Client: Could not get interface IZ.
Client: Get interface IY from interface IX.
QueryInterface: Return pointer to IY.
Client: Succeeded getting IY.
Fy()
Client: Get interface IUnknown from interface IY.
QuerInterface:Return pointer to IUnknown
Are the IUnknown pointers equal? Yes,pIunknownfromIY == pIunknown.
Press any key to continue
*/
其实我们可以把这一个文件按其功能划分为更下的文件,这样对整体结构有个清晰的认识:
接口类 interface.h
#include
<
objbase.h
>
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Interfaces
interface
IX:IUnknown
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
virtual void _stdcall Fx() = 0;
}
;
interface
IY:IUnknown
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
virtual void _stdcall Fy() = 0;
}
;
interface
IZ:IUnknown
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
virtual void _stdcall Fz() = 0;
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
IIDs
static
const
IID IID_IX
=
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
0x32bb8320,0xb41b,0x11cf,...{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}
}
;
static
const
IID IID_IY
=
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
0x32bb8321,0xb41b,0x11cf,...{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}
}
;
static
const
IID IID_IZ
=
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
0x32bb8322,0xb41b,0x11cf,...{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}
}
;
实现类 --头文件CB.h
#ifndef CB_H
#define
CB_H
#include
"
interface.h
"
#include
<
iostream.h
>
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Component
class
CB:
public
IX,
public
IY
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
virtual HRESULT _stdcall QueryInterface(const IID& iid, void** ppv);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
virtual ULONG _stdcall AddRef()...{return 0;}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
virtual ULONG _stdcall Release()...{return 0;}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
//interfac IX implementation
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
virtual void _stdcall Fx()...{cout<<"Fx()"<<endl;}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
//interfac IY implementation
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
virtual void _stdcall Fy()...{cout<<"Fy()"<<endl;}
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
extern
void
trace(
const
char
*
msg);
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
Creation function
extern
IUnknown
*
CreateInstance();
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
#endif
实现类--CB.cpp
#include
"
CB.h
"
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
HRESULT _stdcall CB::QueryInterface(
const
IID
&
iid,
void
**
ppv)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
if (iid == IID_IUnknown)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("QuerInterface:Return pointer to IUnknown");
*ppv = static_cast<IX*>(this);
}
else if(iid == IID_IX)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("QueryInterface: Return pointer to IX.");
*ppv = static_cast<IX*>(this);
}
else if (iid == IID_IY)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("QueryInterface: Return pointer to IY.");
*ppv = static_cast<IY*>(this);
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("QueryInterface: Interface not supported.");
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
void
trace(
const
char
*
msg)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
cout<<msg<<endl;
}
//
Creation function
IUnknown
*
CreateInstance()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
IUnknown* pI = static_cast<IX*>(new CB);
pI->AddRef();
return pI;
}
注意将this指针转换为IUnknown*是不明确的.因为IX和IY都是从IUnknown继承得到的.因此在这种情况下,返回值应该是static_cast<IUnknown*>(static_cast<IX*>(this))或static_cast<IUnknown*>(static_cast<IY*>(this)),不过在上例中其实是无关紧要的,因为它们使用的是同一实现.
客户端代码--App.cpp
#include
"
CB.h
"
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
int
main()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
HRESULT hr;
trace("Client: Get an IUnknown pointer.");
IUnknown* pIUnknown = CreateInstance();
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Get Interface IX.");
IX *pIX = NULL;
hr = pIUnknown->QueryInterface(IID_IX,(void**)&pIX);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Succeeded getting IX.");
pIX->Fx();
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Get Interface IY.");
IY *pIY = NULL;
hr = pIUnknown->QueryInterface(IID_IY,(void**)&pIY);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Succeeded getting IY.");
pIY->Fy();
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Ask for an unsuppoered interface.");
IZ *pIZ = NULL;
hr = pIUnknown->QueryInterface(IID_IZ,(void**)&pIZ);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Succeeded getting IZ.");
pIZ->Fz();
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Could not get interface IZ.");
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Get interface IY from interface IX.");
IY* pIYfromIX = NULL;
hr = pIX->QueryInterface(IID_IY,(void**)&pIYfromIX);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
trace("Client: Succeeded getting IY.");
pIYfromIX->Fy();
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
trace("Client: Get interface IUnknown from interface IY.");
IUnknown* pIUnknownfromIY = NULL;
hr = pIY->QueryInterface(IID_IUnknown,(void**)&pIUnknownfromIY);
if (SUCCEEDED(hr))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
cout<<"Are the IUnknown pointers equal? ";
if (pIUnknownfromIY == pIUnknown)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
cout<<"Yes,pIunknownfromIY == pIunknown."<<endl;
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
cout<<"No,pIUnknownfromIY != pIunknown."<<endl;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
//Delete the component.
delete pIUnknown;
return 0;
}
可以看到,在接口类中,我们定义了三个接口,定义了三个IID.
在具体实现类中,实现了QueryInterface,AddRef,Release三个IUnknown接口,这是COM组件必须实现的接口,另外还实现了Fx和Fy接口.在实现类中实现QueryInterface是必要的,因为只有在实现类中,才知道这个实现类到底实现了哪些接口.
在客户端代码中,通过QueryInterface接口可以查询当前实现类有没有实现某个接口.注意QueryInterface的实现方式.对this指针的类型转换会给ppv不同的值.也就是
(IX
*
)
this
!=
(IY
*
)
this
(
void
*
)
this
!=
(IY
*
)
this
比如如下定义中:
class
CA:
public
IX,
public
IY
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
...
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
void
foo(IX
*
pIX);
void
bar(IY
*
pIY);
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
int
main()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
CA *pA = new CA;
foo(pA);
bar(pA);
delete pA;
return 0;
}
由于CA同时继承了IX和IY,因此可以使用IX或IY指针的地方均可以使用指向CA的指针.例如可以将指向CA的指针传给接收IX或IY指针的函数,这样此函数仍将能正常工作.foo需要一个指向合法的IX的虚拟函数表的指针,而bar则需要一个指向IY虚拟函数表的指针.这两个虚拟函数表的内容是不一样的.因此将一个IX vtbl传给bar时,此函数不能正常工作.因此编译器将同一指针传给foo和bar是不可能的,它必须对CA的指针进行修改以便它指向一个合适的vtbl指针.下图显示了类CA的内存结构.
![](https://p-blog.csdn.net/images/p_blog_csdn_net/sibylle/未命名.jpg)
由上图可以看出,CA的this指针指向IX的虚拟函数表.因此可以在不改变CA的this指针的值的情况下用它来代替IX指针.但也可以很明显的看出,CA的this指针并没有指向IY的虚拟函数表指针.因此将指向类CA的指针传给一个接收IY指针的函数之前,其值必须修改.为完成这种修改,编译器将把IY虚拟函数表指针的偏移量加到CA的this指针上.