学C++已经有一段时间了,但是对一些东西的理解任然停留在书本上,没有更深刻的认识。比如如题。
曾有人问过我构造函数的作用是干什么的?回答很简单:“用来构造对象的”。于是满脑子就形成了这样
一种认识:一个对象只有在调用了构造函数以后,它所对应的内存块才有效。此思想存在了相当长的时间,
可以说直到写这篇文章前夕。我们在写构造函数时,如果构造函数形参和类成员变量同名,我们会用this
指针来加以区分。这从某种程度上已经暗示了调用构造函数时,类对象已经存在了。奈何思想顽固,对此
而不见。
下面从汇编的角度来说明,对象其实在调用构造函数之前就已经存在了。
在主函数 A gg;插入断点,运行,Alt + 8 ,查看底层的汇编代码。
24: A gg;
004038D8 lea ecx,[ebp-8]
004038DB call @ILT+720(A::A) (004012d5)
25: return 0;
004038E0 mov dword ptr [ebp-0Ch],0
004038E7 lea ecx,[ebp-8]
004038EA call @ILT+740(A::~A) (004012e9)
004038EF mov eax,dword ptr [ebp-0Ch]
26: }
首先对上面的汇编代码做以下说明:
这是main函数中的一段代码, 24 , 25 , 26分别对应着主函数中的A gg、return 0、 }
当调试停在004038D8指令上时,我们查看 &gg的值 为 0x0012FF78,说明对象已经存在了。
也就是说构造函数只是类对象第一个调用的函数,而不是构造类对象内存块的家伙。
至于对象gg的析构是在 return 0;后调用的,注意看指令 004038EA 调用了类的析构函数,不过
掉了类的析构函数并不意味着对象对应的内存块就无效了!对象gg对应的内存块无效要等到 26以后。
这会在另一篇关于对析构函数的认识中说明。
曾有人问过我构造函数的作用是干什么的?回答很简单:“用来构造对象的”。于是满脑子就形成了这样
一种认识:一个对象只有在调用了构造函数以后,它所对应的内存块才有效。此思想存在了相当长的时间,
可以说直到写这篇文章前夕。我们在写构造函数时,如果构造函数形参和类成员变量同名,我们会用this
指针来加以区分。这从某种程度上已经暗示了调用构造函数时,类对象已经存在了。奈何思想顽固,对此
而不见。
下面从汇编的角度来说明,对象其实在调用构造函数之前就已经存在了。
#include
<
iostream
>
using namespace std;
class A
{
public:
A( )
{
mem = 1;
};
virtual ~A( )
{
mem = 0;
};
int mem;
} ;
int main( )
{
A gg;
return 0;
}
using namespace std;
class A
{
public:
A( )
{
mem = 1;
};
virtual ~A( )
{
mem = 0;
};
int mem;
} ;
int main( )
{
A gg;
return 0;
}
24: A gg;
004038D8 lea ecx,[ebp-8]
004038DB call @ILT+720(A::A) (004012d5)
25: return 0;
004038E0 mov dword ptr [ebp-0Ch],0
004038E7 lea ecx,[ebp-8]
004038EA call @ILT+740(A::~A) (004012e9)
004038EF mov eax,dword ptr [ebp-0Ch]
26: }
首先对上面的汇编代码做以下说明:
这是main函数中的一段代码, 24 , 25 , 26分别对应着主函数中的A gg、return 0、 }
当调试停在004038D8指令上时,我们查看 &gg的值 为 0x0012FF78,说明对象已经存在了。
也就是说构造函数只是类对象第一个调用的函数,而不是构造类对象内存块的家伙。
至于对象gg的析构是在 return 0;后调用的,注意看指令 004038EA 调用了类的析构函数,不过
掉了类的析构函数并不意味着对象对应的内存块就无效了!对象gg对应的内存块无效要等到 26以后。
这会在另一篇关于对析构函数的认识中说明。