c++构造函数的背后

OS winxp 、平台:i386

/*

* 以下是测试代码

*/

/*


* class obj 
*/
class obj
{
public:
     int m_i;
     int *m_pi;
     obj(int *ptemp)
     {

        printf("this point to %x/n" , (unsigned int)this );
        m_i = 0;
        printf("address of m_i = %x/n" , (unsigned int)&m_i );
        this->m_pi = ptemp;
        printf("address of m_pi = %x/n" , (unsigned int)&m_pi);
     }
     void funcA()
    {
         printf("this is funcA/n");
    }
 
    void funcB()
   {
        printf("this is funcB/n");
   }
   virtual void vfunc()
   {
        printf("this is virtual func");
   }
   ~obj()
   {
   }
};

/* main */

  int main(int arg , char *argv[])

  {

  int n = 2 ;
  obj *po = new obj(&n);
  cout<<"***after construt***"<<endl;
  printf("address of po = %x " , (unsigned int)po );
  cout<<po->m_i<<endl;
  cout<<*po->m_pi<<endl; 
  delete po ;

}

1.初始化过程:

我们知道类的对象初始化需要调用类的构造函数。那么这个过程是怎么样的呢?我们先来看看对象的初始化过程。 

(一) obj *po new obj(&n) ;

对应汇编:

00401C23 0F BF 0D 5C 55 41 00    movsx       ecx,word ptr [`main'::`2'::__LINE__Var (0041555c)]

00401C2A 83 C1 11                         add         ecx,11h

00401C2D 51                                   push        ecx

00401C2E 68 20 55 41 00             push        offset THIS_FILE (00415520)

00401C33 6A0C                              push        0Ch

00401C35 E8 80 FB FF FF              call        operator new (004017ba)/*1 调用operator newnew操作符)分配了sizeof(obj)大小的内存空间。*/

00401C3A 83 C4 0C                        add         esp,0Ch

00401C3D 89 45 E0                         mov         dword ptr [ebp-20h],eax    /*2.eax中保存了返回的内存起始地址指针,此处把起始地址指针保存在[ebp-20h]中。现在我们记住eax的值,我这里是0x00421110,后面有用*/

00401C40 C7 45 FC 00 00 00 00    mov         dword ptr [ebp-4],0

00401C47 83 7D E0 00                   cmp         dword ptr [ebp-20h],0    /*3 这里判断分配的地址是否为空,和我们通常在分配完内存后所作的判断一样*/

00401C4B 74 11                              je          main+12Eh (00401c5e)

00401C4D 8D 55 EC                       lea         edx,[n]

00401C50 52                                  push      edx    /*obj的构造函数的参数入栈,为调用构造函数作准备*/

00401C51 8B 4D E0                       mov       ecx,dword ptr [ebp-20h]

/*参数保存在寄存器cx*/

00401C54 E8 D4 F3 FF FF            call        @ILT+40(obj::obj) (0040102d) /*呵呵,开始了。进入obj构造函数的调用*/

 我们仍然来看能给我们提示的关键语句:

(二)printf("this point to %x/n" , (unsigned int)this );

00401A91 8B F4                             mov         esi,esp

00401A93 8B 55 FC                        mov         edx,dword ptr [ebp-4]

00401A96 52                                   push        edx

00401A97 68 6C 41 41 00               push        offset string "this point to %x/n" (0041416c)

/*按函数调用方式__cdecl ,参数(unsigned int)this)先入栈,在我这里,从memory中可以看到ebp-4 = 12fee4 ,[ebp-4] = 421110 ,这就是前面通过operator new分配的内存首址,也就是说obj *po此时指向的地址。在obj的构造函数里,obj *po完成一系列的初始化工作。*/

00401A9C FF 15 D4 62 41 00         call        dword ptr [__imp__printf (004162d4)]

00401AA2 83 C4 08                         add         esp,8

00401AA5 3B F4                              cmp         esi,esp

00401AA7 E8 26 FD FF FF              call        _chkesp (004017d2)

    从以上分析我们可以看出,obj *po首先由operator new分配内存地址,然后以内存地址作为参数调用obj构造函数,也就是说在调用构造函数以前,对象的内存布局就已经完成.基本上我们的分析到这里就可以结束了.对于c++构造函数背后做的事我们也可以有一个比较清晰的认识了吧!

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章