部分参考:http://blog.csdn.net/devilkin64/article/details/5939613
虚函数表的建立是取决于定义类的时候是否包含虚函数,如果有类函数/ 方法声明为虚,则改类会建立一张虚表.在网上找到一个牛人用汇编的方法论证虚 表是存放在常量区内(具体论证就省略,否则就扯远了). 继承类会同样建立一张虚表,并将覆盖虚表中父类虚函数的地址.
在编译阶段,编译器为每个包含虚函数的类创建一个虚表,这个类的所有对象中的虚表指针,都指向这同一份虚表;一般虚表指针放在对象的开始位置;
虚函数表是在代码编译生成,程序载入内存的时候,放在内存常量区.
虚函数指针是在对象建立时由构造函数生成并保存于对象地 址首部.
虚函数指针:虚函数指针是在实例化对象 的时候由构造函数生成的指向虚表的指针.放在对象地址的首位. 下面代码用于显 示虚表及虚表指针.
class base
{
public:
int a;
virtual void Print()
{
cout<<"in base print\n";
}
};
class d1:public base
{
public:
void Print()
{
cout<<"in d1 print\n";
}
void d1Print()
{
cout<<"d1 self print \n";
}
};
class d2:public d1
{
public:
void Print()
{
cout<<"in d2 print\n";
}
void d2Print()
{
cout<<"d2 self print \n";
}
};
typedef void (*pfun)();
int main()
{
base *md2 = new d2;
md2->Print();
d1 *md1 = new d2;
md1->Print();
//上面两个例子说明,虚函数具有向下传递的特性;只要在最开始的基类中定义虚函数,则其他所有的子孙类都默认是虚函数
int *p2 =(int *) md2;//md2本来是指向对象的一个指针,将此指针转换为指向一个int数组的指针,这样就能像访问数组一样访问对象里面的数据
cout<<*p2<<endl;//*p2是指放在对象md2中第一个位置的元素的值,这个值就是虚表的地址
p2 =(int *)(*p2);//*p2是虚表的地址,也就是指虚表的指针,我们要把虚表也表示成数组的形式,把指向虚表的指针转换为指向一个Int数组的指针
printf("%x\n",p2);//
cout<<p2<<endl;//
printf("%d\n",p2);//上面三个输出的值都是相等的,只不过是十进制或者十六进制表示的不同
(pfun(*p2))();
int *p1 = (int *) md1;
cout<<*p1<<endl;//上面所有的输出都是显示的是类d2的虚表的地址,也就是说不管类有多少个对象,但是虚表只有一份
/*int i =0;
int *p = &i;
cout<<&i<<" "<<p<<endl;*/
delete md1;
delete md2;
}