vptr的初始化

来源:互联网 发布:减脂练马甲线软件 编辑:程序博客网 时间:2024/05/18 05:39

class base
{
 int i;
public:
 base(int I):i(I){}
 virtual int sum(){return i;}

};
 

主程序


 base b(100);

 b.sum();

看base的构造函数

class base
{
 int i;
public:
 base(int I):i(I){}
00401250  push        ebp 
00401251  mov         ebp,esp
00401253  push        ecx 
00401254  mov         dword ptr [ebp-4],ecx
00401257  mov         eax,dword ptr [this]                 
0040125A  mov         dword ptr [eax],offset base::`vftable' (402164h)   //对象首地址写入offset vftable
00401260  mov         ecx,dword ptr [this]
00401263  mov         edx,dword ptr [I]                                                          //i 写入edx
00401266  mov         dword ptr [ecx+4],edx                                                //edx写入首地址+4
00401269  mov         eax,dword ptr [this]                                                   //返回this
0040126C  mov         esp,ebp
0040126E  pop         ebp 
0040126F  ret         4   

我们看到内存  402164放着401280

 virtual int sum(){return i;}
00401280  push        ebp 
00401281  mov         ebp,esp
00401283  push        ecx 
00401284  mov         dword ptr [ebp-4],ecx
00401287  mov         eax,dword ptr [this]
0040128A  mov         eax,dword ptr [eax+4]
0040128D  mov         esp,ebp
0040128F  pop         ebp 
00401290  ret   

现在有了个小结论:

vptr的初始化在构造函数内,由编译器悄悄生成, 成员初始化之前,问题来了 如果在构造函数内调用未被初始化的成员,会发生什么?

 什么都没发生,一切正常

class base
{
 int i;
public:
 base(int I):i(I){add();}
00401250  push        ebp 
00401251  mov         ebp,esp
00401253  push        ecx 
00401254  mov         dword ptr [ebp-4],ecx
00401257  mov         eax,dword ptr [this]
0040125A  mov         dword ptr [eax],offset base::`vftable' (402164h)
00401260  mov         ecx,dword ptr [this]
00401263  mov         edx,dword ptr [I]
00401266  mov         dword ptr [ecx+4],edx
00401269  mov         ecx,dword ptr [this]
0040126C  call        base::add (4012A0h)                     //不论是不是虚函数,都在成员初始化之后
00401271  mov         eax,dword ptr [this]
00401274  mov         esp,ebp
00401276  pop         ebp 
00401277  ret         4  

不清楚各个编译器的是不是不同,这是我在vc2005下的结果

 再看派生类的,从汇编可以看出,是用派生类的vptr 代替了base的vptr

 base(int I):i(I){printf("base vptr=%x",*(int*)this);}

 derived(int I,int J):base(I),j(J) {printf("derived vptr=%x",*(int*)this);}

在构造函数里直接输出了vptr

  base(int I):i(I){printf("base vptr=%x",*(int*)this);}
00401260  push        ebp 
00401261  mov         ebp,esp
00401263  push        ecx 
00401264  mov         dword ptr [ebp-4],ecx
00401267  mov         eax,dword ptr [this]
0040126A  mov         dword ptr [eax],offset base::`vftable' (402174h)
00401270  mov         ecx,dword ptr [this]
00401273  mov         edx,dword ptr [I]
00401276  mov         dword ptr [ecx+4],edx
00401279  mov         eax,dword ptr [this]
0040127C  mov         ecx,dword ptr [eax]
0040127E  push        ecx 
0040127F  push        offset string "base vptr=%x" (402160h)
00401284  call        dword ptr [__imp__printf (4020ACh)]
0040128A  add         esp,8
0040128D  mov         eax,dword ptr [this]
00401290  mov         esp,ebp
00401292  pop         ebp 
00401293  ret         4   

class derived:public base
{
 int j;
public:
 derived(int I,int J):base(I),j(J) {printf("derived vptr=%x",*(int*)this);}
004012C0  push        ebp 
004012C1  mov         ebp,esp
004012C3  push        ecx 
004012C4  mov         dword ptr [ebp-4],ecx
004012C7  mov         eax,dword ptr [I]
004012CA  push        eax 
004012CB  mov         ecx,dword ptr [this]
004012CE  call        base::base (401260h)
004012D3  mov         ecx,dword ptr [this]
004012D6  mov         dword ptr [ecx],offset derived::`vftable' (40218Ch)
004012DC  mov         edx,dword ptr [this]
004012DF  mov         eax,dword ptr [J]
004012E2  mov         dword ptr [edx+8],eax
004012E5  mov         ecx,dword ptr [this]
004012E8  mov         edx,dword ptr [ecx]
004012EA  push        edx 
004012EB  push        offset string "derived vptr=%x" (402178h)
004012F0  call        dword ptr [__imp__printf (4020ACh)]
004012F6  add         esp,8
004012F9  mov         eax,dword ptr [this]
004012FC  mov         esp,ebp
004012FE  pop         ebp 
004012FF  ret         8   

主程序

base b(100);

derived d(200,400);

结果输出了3个

base vptr=402174 base vptr=402174 derived vptr=40218c

是不是跟你想的一样?

原创粉丝点击