对象的构造与虚表

假设有这样的类

 1 class Base
 2 {
 3 public:
 4     Base()
 5     {
 6         clear();
 7     }
 8     virtual ~Base()
 9     {
10         int a = 0;
11     }
12     virtual void fun()
13     {
14         cout << "base" << endl;
15     }
16     void clear()
17     {
18         memset(this,0,sizeof Base);
19     }
20     int m_int32;
21 };
22 class child : public Base
23 {
24 public:
25     virtual ~child()
26     {
27         int a = 0;
28     }
29     virtual void fun()
30     {
31         cout << "child" << endl;
32     }
33 };

vs会把父类,子类的虚表地址存在代码段

每次构造函数和析构函数调用之前,会把各自的虚表地址设回去,

父类析构:

1 00411B36  mov         dword ptr [eax],offset Base::`vftable' (417814h) 
2         int a = 0;
3 00411B3C  mov         dword ptr [a],0 

父类构造:

00411976  mov         dword ptr [eax],offset Base::`vftable' (417814h) 
    {
        clear();
0041197C  mov         ecx,dword ptr [this] 
0041197F  call        Base::clear (411127h) 
    }

子类构造:

00411916  call        Base::Base (411145h) 
0041191B  mov         eax,dword ptr [this] 
0041191E  mov         dword ptr [eax],offset child::`vftable' (417808h) 
00411924  mov         eax,dword ptr [this] 

可得出以下结论:

当new 一个子类时,编译器已经把父类及子类的虚表入口地址保存在代码段中,父类及子类各有一份虚表,也已经在构造之前赋值(子类前面有一些值还不清楚)。

this指针保存的是这个新建类的地址,头4个字节存放虚表的入口地址,先构造父类,把父类的虚表入口地址赋值。按照上面程序例子,之后把父类大小的区域置0。在构造子类,把子类的虚表入口地址写入。

析构的时候,自底向上析构,编译器会先把本类的虚表入口地址赋值,这样做是为了正确的析构本类,因为如果不重新赋值,那就可能调用子类的函数,而此时子类已经析构完成了。

在构造和析构函数中,不能使用虚函数,原因就是每次构造和析构,编译器都会在之前把本类的虚函数入口值重新设置,调用虚函数是没有意义的

转载于:https://www.cnblogs.com/xubin0523/archive/2012/11/13/2767561.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值