#include
using namespace std;
class Base
{
public:
Base(int a) :ma(a)
{
//clear()前要是vfptr已经指向vftable,则程序崩溃
//因为虚表已经写入了,但是置空了,vfptr指向为空,
//虚函数无法找到vfptr,无法找到虚表,无法找到虚函数入口地址,无法到寄存器
//vfptr->vftable
clear();
//vfptr=NULL
cout << "Base::Base(int)" << endl;
}
~Base()
{
cout << "Base::~Base()" << endl;
}
virtual void show()
{
cout << "Base::show()" << endl;
cout << "ma:" << ma << endl;
}
void clear()
{
memset(this, 0, sizeof(*this));
}
protected:
int ma;
};
class Derive :public Base
{
public:
Derive(int b) :mb(b), Base(b)
{
cout << "Derive::Derive(int)" << endl;
}
~Derive()
{
cout << "Derive::~Derive()" << endl;
cout << "ma:" << ma << endl;
cout << "mb:" << mb << endl;
}
void show()
{
cout << "Derive::show()" << endl;
}
private:
int mb;
};
int main()
{
Base b(10);
Derive d(20);
Base* pb1 = &b;
pb1->show();
}
实际上以下是我们希望发生的情况,首先将vfptr置空,然后vfptr指向vftable,这样指向就正确了。
clear();
//vfptr=NULL
//vfptr->vftable
cout << "Base::Base(int)" << endl;
但是事实上并未如此,程序崩溃了(访问了保留区的数据<0地址位保留区,我们不能访问>),说明虚表的写入时机(vfptr=&vftable,即就是什么时候用vfptr指向vftable???前提是基类和派生类中均有虚函数)为构造函数第一行代码执行之前。
为什么是构造函数???对象生成,开辟内存空间,有对象,才会有vfptr的地址,vfptr才有地址存放,调用构造函数才对vfptr进行赋值,虚表才写入。
int main()
{
Base b(10);
Derive d(20);
Base* pb2 = &d;
pb2->show();
}
发现在此程序不崩溃,原因???
先构造基类部分,让虚表指向基类的vfptr,一指向就让它置空,此时派生类对象生成,就让vfptr指向派生类自己的虚表,这下指向就不为空了(虚表写入了两次)
分析:
一、编译期间(语法语义分析)生成虚表
1、扫描定义点的时候生成vftable
(扫描class Base整个类,里边有虚函数,然后放到vftable中)
2、扫描调用点
结合上下文分析调用方式(call eax 还是 call 函数入口地址,确定是动态绑定还是静态绑定)
二、运行期间
到调用点确定是动态绑定
Base* pb = new Derive(10);
pb->show();
需要看pb类中有无虚函数以及函数类型(show()方法的类型是不是虚函数)