当使用多重继承时,C++ 必须维护多个 vtable,这导致对公共基类有“多个视图”。
这是一个代码片段:
#include "stdafx.h"
#include <Windows.h>
void dumpPointer( void* pointer )
{
__int64 thisPointer = reinterpret_cast<__int64>( pointer );
char buffer[100];
_i64toa( thisPointer, buffer, 10 );
OutputDebugStringA( buffer );
OutputDebugStringA( "\n" );
}
class ICommonBase {
public:
virtual void Common() = 0 {}
};
class IDerived1 : public ICommonBase {
};
class IDerived2 : public ICommonBase {
};
class CClass : public IDerived1, public IDerived2 {
public:
virtual void Common() {
dumpPointer( this );
}
int stuff;
};
int _tmain(int argc, _TCHAR* argv[])
{
CClass* object = new CClass();
object->Common();
ICommonBase* casted1 = static_cast<ICommonBase*>( static_cast<IDerived1*>( object ) );
casted1->Common();
dumpPointer( casted1 );
ICommonBase* casted2 = static_cast<ICommonBase*>( static_cast<IDerived2*>( object ) );
casted2->Common();
dumpPointer( casted2 );
return 0;
}
它产生以下输出:
206968 //CClass::Common this
206968 //(ICommonBase)IDerived1::Common this
206968 //(ICommonBase)IDerived1* casted1
206968 //(ICommonBase)IDerived2::Common this
206972 //(ICommonBase)IDerived2* casted2
here casted1
and casted2
具有不同的值,这是合理的,因为它们指向不同的子对象。当虚函数被调用时,到基类的转换已经完成,编译器不知道它最初是一个最派生的类。仍然this每次都一样。这是怎么发生的?
当在虚函数调用中使用多重继承时,对虚函数的调用通常会转到一个“thunk”,该“thunk”会调整this
指针。在你的例子中,casted1
指针的 vtbl 条目不需要 thunk 因为IDerived1
的子对象CClass
恰好与 CClass 对象的开始一致(这就是为什么casted1
指针值与CClass
object
指针)。
但是,那casted2
指向的指针IDerived2
子对象与开头不一致CClass
对象,所以vtbl函数指针实际上指向一个thunk而不是直接指向CClass::Common()
功能。 thunk 调整this
指向实际的指针CClass
然后对象跳转到CClass::Common()
功能。所以它总是会得到一个指向开始的指针CClass
对象,无论它是从哪种类型的子对象指针调用的。
S里对此有很好的解释tanley Lippman 的《C++ 对象模型内部》一书 http://www.informit.com/store/product.aspx?isbn=0201834545,第 4.2 节“虚拟成员函数/MI 下的虚拟函数”。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)