今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的...

本文对比了C++中成员变量初始化列表与构造函数体内初始化的不同方式,并通过具体实例和汇编代码展示了两者在实际编译过程中的等效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

好久没来了,准备毕业、毕业答辩、毕业、找工作、现在终于稳定下来。突然想到一个问题,随便测试下写写,不要拍砖哈

编译器:VC2005  Release模式,代码不优化
调试器: OllyDBG 1.10
程序如下:

None.gif class  A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif A();
InBlock.gif 
~A();
InBlock.gif 
int a;
InBlock.gif 
long b;
ExpandedBlockEnd.gif}
;
None.gif
class  B
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif B();
InBlock.gif 
~B();
InBlock.gif 
int a;
InBlock.gif 
long b;
ExpandedBlockEnd.gif}
;
None.gifA::A() : a(
0 )
None.gif ,b(
- 1 )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedBlockEnd.gif}

None.gifA::
~ A()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedBlockEnd.gif}

None.gifB::B() 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif a 
= 1;
InBlock.gif b 
= -2;
ExpandedBlockEnd.gif}

None.gifB::
~ B()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedBlockEnd.gif}

None.gif
int  main()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif __asm
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif  push eax   
//加些标记,方便辨认
InBlock.gif
  add esp,4
ExpandedSubBlockEnd.gif }

InBlock.gif A a;
InBlock.gif __asm
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif  push ebx   
//加些标记,方便辨认
InBlock.gif
  push ebx
InBlock.gif  add esp,
8
ExpandedSubBlockEnd.gif }

InBlock.gif B b;
InBlock.gif 
InBlock.gif 
return 0;
ExpandedBlockEnd.gif}

对应的汇编及分析如下:
对应的汇编及分析如下:
 
None.gif 对应的汇编及分析如下:
None.gif 
None.gif
// 类A的构造函数
None.gif
00401000    / $   55             push    ebp            // 将当前栈基址压栈保存
None.gif
00401001    | .  8BEC          mov     ebp, esp       // 将当前栈指针作为栈基址
None.gif
00401003    | .   51             push    ecx         // this指针压栈
None.gif
00401004    | .  894D FC       mov     dword ptr [ebp - 4 ], ecx      // 保存this指针
None.gif
00401007    | .  8B45 FC       mov     eax, dword ptr [ebp - 4 ]      // this指针放入eax
None.gif
0040100A   | .  C700  00000000  mov     dword ptr [eax],  0           // this指针指向的地址存入0,也就是变量a,对应语句*(int*)this=0;
None.gif
00401010    | .  8B4D FC       mov     ecx, dword ptr [ebp - 4 ]      // this指针放入ecx(多余的一步)
None.gif
00401013    | .  C741  04  FFFFF > mov     dword ptr [ecx + 4 ],  - 1        // this指针指向的地址存入-1,也就是变量b,对应语句*(int*)(this+4)=-1;
None.gif
0040101A   | .  8B45 FC       mov     eax, dword ptr [ebp - 4 ]      // 返回值放入eax
None.gif
0040101D   | .  8BE5          mov     esp, ebp                    // 还原先前的esp、ebp
None.gif
0040101F   | .  5D            pop     ebp
None.gif
00401020   \.  C3            retn
None.gif
// 中间代码省略
None.gif
// 类B的构造函数,和a的一模一样
None.gif
00401030    / $   55             push    ebp
None.gif
00401031    | .  8BEC          mov     ebp, esp
None.gif
00401033    | .   51             push    ecx
None.gif
00401034    | .  894D FC       mov     dword ptr [ebp - 4 ], ecx
None.gif
00401037    | .  8B45 FC       mov     eax, dword ptr [ebp - 4 ]
None.gif0040103A  
| .  C700  01000000  mov     dword ptr [eax],  1
None.gif
00401040    | .  8B4D FC       mov     ecx, dword ptr [ebp - 4 ]
None.gif
00401043    | .  C741  04  FEFFF > mov     dword ptr [ecx + 4 ],  - 2
None.gif0040104A  
| .  8B45 FC       mov     eax, dword ptr [ebp - 4 ]
None.gif0040104D  
| .  8BE5          mov     esp, ebp
None.gif0040104F  
| .  5D            pop     ebp
None.gif
00401050   \.  C3            retn
None.gif
// 中间代码省略
None.gif
// 2个类公用一个析构函数
None.gif
00401060    / $   55             push    ebp
None.gif
00401061    | .  8BEC          mov     ebp, esp
None.gif
00401063    | .   51             push    ecx
None.gif
00401064    | .  894D FC       mov     dword ptr [ebp - 4 ], ecx
None.gif
00401067    | .  8BE5          mov     esp, ebp
None.gif
00401069    | .  5D            pop     ebp
None.gif0040106A  \.  C3            retn
None.gif
// 中间代码省略
None.gif
// main()函数
None.gif
00401070    / $   55             push    ebp
None.gif
00401071    | .  8BEC          mov     ebp, esp
None.gif
00401073    | .  83EC  14        sub     esp,  14     // 给变量分配20字节空间
None.gif
00401076    | .   50             push    eax       // 刚才的代码标记
None.gif
00401077    | .  83C4  04        add     esp,  4     // 刚才的代码标记
None.gif
0040107A   | .  8D4D F8       lea     ecx, dword ptr [ebp - 8 ]       // thiscall调用约定,this指针通过ecx传递
None.gif
0040107D   | .  E8 7EFFFFFF   call     00401000          // 调用A构造函数
None.gif
00401082    | .   53             push    ebx      // 刚才的代码标记
None.gif
00401083    | .   53             push    ebx     // 刚才的代码标记
None.gif
00401084    | .  83C4  08        add     esp,  8     // 刚才的代码标记
None.gif
00401087    | .  8D4D F0       lea     ecx, dword ptr [ebp - 10 ]      // thiscall调用约定,this指针通过ecx传递    
None.gif
0040108A   | .  E8 A1FFFFFF   call     00401030     // 调用B构造函数
None.gif
0040108F   | .  C745 EC  00000 > mov     dword ptr [ebp - 14 ],  0        // 函数返回值预先存储好
None.gif
00401096    | .  8D4D F0       lea     ecx, dword ptr [ebp - 10 ]
None.gif
00401099    | .  E8 C2FFFFFF   call     00401060                   // 调用B析构函数
None.gif
0040109E   | .  8D4D F8       lea     ecx, dword ptr [ebp - 8 ]
None.gif004010A1  
| .  E8 BAFFFFFF   call     00401060                   // 调用A析构函数
None.gif
004010A6   | .  8B45 EC       mov     eax, dword ptr [ebp - 14 ]    // 返回值最后放入eax
None.gif
004010A9   | .  8BE5          mov     esp, ebp
None.gif004010AB  
| .  5D            pop     ebp
None.gif004010AC  \.  C3            retn

由此可见,成员变量放在初始化列表和构造函数体内,汇编代码是一样的,也就是不管放在那里,是没有差别的
posted on 2008-08-07 16:09 greatws 阅读(2482) 评论(12)   编辑  收藏 引用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpongo11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值