每个含有虚函数的类有一张虚函数表(vtbl),表中每一项指向一个虚函数的地址,实现上是一个函数指针的数组。
虚函数表既有继承性又有多态性。每个派生类的vtbl继承了它各个基类的vtbl,如果基类vtbl中包含某一项,则其派生类的vtbl中也将包含同样的一项,但是两项的值可能不同。如果派生类重载(override)了该项对应的虚函数,则派生类vtbl的该项指向重载后的虚函数,没有重载的话,则沿用基类的值。
在类对象的内存布局中,首先是该类的vtbl指针,然后才是对象数据。在通过对象指针调用一个虚函数时,编译器生成的代码将先获取对象类的vtbl指针,然后调用vtbl中对应的项。对于通过对象指针调用的情况,在编译期间无法确定指针指向的是基类对象还是派生类对象,或者是哪个派生类的对象。但是在运行期间执行到调用语句时,这一点已经确定,编译后的调用代码能够根据具体对象获取正确的vtbl,调用正确的虚函数,从而实现多态性。这完全是编译器的显示问题,你完全可以通过指针操作把虚表中的每一项取出来看看。
------------------------------------------------------------------------------------------------------
Derived *p = new Derived()
int* addr = reinterpret_cast<int*>(p);
int* vptr = reinterpret_cast<int*>(*addr);
//取虚表中的各项:
int* func1 = reinterpret_cast<int*>(vptr[0]);
int* func2 = reinterpret_cast<int*>(vptr[1]);
然后在DEBUG查看func1,func2的值,我当时碰到这个问题就这么干的,有点麻烦,也许有更好的办法把。