虚函数的实现原理问题
digu 2007-11-19 04:07:55 我的理解:
每当创建一个包含有虚函数的类或从包含有虚函数的类派生一个类时,编译器就为这个类创建一个虚函数表(VTABLE)保存该类所有虚拟函数的地址, 当构造该派生类对象时,其成员VPTR被初始化指向该派生类的VTABLE。所以可以认为VTABLE是该类的所以对象共有的,在定义该类是被初始化;而VPTR则是每个类对象都有独立一份的,且在该类对象被构造时被初始化。
然后我们就可以很容易的解释为什么动态绑定不能使用类对象(通过基类对象调用派生类实现虚拟函数),因为该基类对象在构造时其VPTR就指向了基类的VTABLE;而使用基类的指针或者引用,如果认为该类构造是发生在调用该类虚拟函数时也是不正确的,下面这段测试代码证明了这一点:
#include <iostream>
using namespace std;
class base
{
public:
void bfun(){cout<<"call base"<<endl;}
virtual void vfun1(){cout<<"base"<<endl;}
private:
int a;
};
class derived : public base
{
public:
virtual void vfun1(){cout<<"derived"<<endl;}
private:
int b;
};
void display(base *pbase)
{
pbase->bfun();
pbase->vfun1();
}
int main()
{
derived *pb = new derived;
display(pb);
return 0;
}
输出:call base
derived
我现在最大的问题:对于派生类对象的构造(VPTR的初始化)是在什么时候发生的,因为派生类对象VPTR一定要指向派生类的VTABLE。
《C++编程思想》里面说“通过基类指针做虚函数调用时(也就是做多态调用时),编译器静态地插入取得这个V P T R,并在V TA B L E表中查找函数地址的代码,这样就能调用正确的函数使晚捆绑发生。”,我个人的感觉是这里有点问题——编译器静态的取得的这个VPTR是基类的VPTR还是派生类的VPTR,如果是基类的VPTR,那么又如何调用派生类实现的虚拟函数,而如果是派生的VPTR,那么这里编译器又如何可能静态的通过基类指针取得派生类的VPTR呢?