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) ;
对应汇编:
00401C 23 0F BF 0D 5C 55 41 00 movsx ecx,word ptr [`main'::`2'::__LINE__Var ( 0041555c )]
00401C 2A 83 C 1 11 add ecx,11h
00401C 2D 51 push ecx
00401C 2E 68 20 55 41 00 push offset THIS_FILE (00415520)
00401C 33 6A 0C push 0Ch
00401C 35 E8 80 FB FF FF call operator new (004017ba)/*1 调用operator new(new操作符)分配了sizeof(obj)大小的内存空间。*/
00401C 3A 83 C 4 0C add esp,0Ch
00401C 3D 89 45 E0 mov dword ptr [ebp-20h],eax /*2.eax中保存了返回的内存起始地址指针,此处把起始地址指针保存在[ebp-20h]中。现在我们记住eax的值,我这里是0x00421110,后面有用*/
00401C 40 C 7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
00401C 47 83 7D E0 00 cmp dword ptr [ebp-20h],0 /*3 这里判断分配的地址是否为空,和我们通常在分配完内存后所作的判断一样*/
00401C 4B 74 11 je main+12Eh ( 00401c 5e)
00401C 4D 8D 55 EC lea edx,[n]
00401C 50 52 push edx /*obj的构造函数的参数入栈,为调用构造函数作准备*/
00401C 51 8B 4D E0 mov ecx,dword ptr [ebp-20h]
/*参数保存在寄存器cx*/
00401C 54 E8 D 4 F 3 FF FF call @ILT+40(obj::obj) (0040102d) /*呵呵,开始了。进入obj构造函数的调用*/
我们仍然来看能给我们提示的关键语句:
(二)printf("this point to %x/n" , (unsigned int)this );
00401A 91 8B F4 mov esi,esp
00401A 93 8B 55 FC mov edx,dword ptr [ebp-4]
00401A 96 52 push edx
00401A 97 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完成一系列的初始化工作。*/
00401A 9C FF 15 D4 62 41 00 call dword ptr [__imp__printf (004162d4)]
00401AA2 83 C 4 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++构造函数背后做的事我们也可以有一个比较清晰的认识了吧!