随笔-16  评论-116  文章-0  trackbacks-0

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

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

class A
{
public:
 A();
 
~A();
 
int a;
 
long b;
}
;
class B
{
public:
 B();
 
~B();
 
int a;
 
long b;
}
;
A::A() : a(
0)
 ,b(
-1)
{
}

A::
~A()
{
}

B::B() 
{
 a 
= 1;
 b 
= -2;
}

B::
~B()
{
}

int main()
{
 __asm
 
{
  push eax   
//加些标记,方便辨认
  add esp,4
 }

 A a;
 __asm
 
{
  push ebx   
//加些标记,方便辨认
  push ebx
  add esp,
8
 }

 B b;
 
 
return 0;
}

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

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

评论:
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 17:37 | 沈臻豪(foxtail)
请牛人鉴定一下吧 我记得是不一样的 一种是初始化 一种是赋值
不一样的吧。  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 17:40 |
你别用调试器也可以看出来效果.方法是每个默认构造函数里面加一个打印语句,然后再写一个有参数的构造函数,也打印语句.看看你把对这些类的构造放在函数体内是不是先调用了默认构造函数再调用带参数的构造函数就行了.
  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 18:02 | 过客
给你一个测试代码,你就会发现你是错误的:
using namespace std;


class A {
private:
int aa;
public:
A():aa(0) {
cout << "In A::A()" << endl;
}
A(int a):aa(a) {
cout << "In A::A(int a)" << endl;
}
int operator=(int a) {
cout << "In A::=" << endl;aa = a;
return a;
}
};

class B {
private:
A aa;
public:
B() {
cout << "In B::B()" << endl;
aa = 3;
}
B(int a) : aa(a) {
cout << "In B::B(int a)" << endl;
}
};

int main(int argc, char **argv, char **env) {
B b;
cout << endl;
B b2(3);
return 0;
}
================================
运行结果:
In A::A()
In B::B()
In A::=

In A::A(int a)
In B::B(int a)
  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 18:03 | 过客
为什么是乱的?前面的TAB怎么没有了?  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 18:04 | 过客
[CODE]
using namespace std;


class A {
private:
int aa;
public:
A():aa(0) {
cout << "In A::A()" << endl;
}
A(int a):aa(a) {
cout << "In A::A(int a)" << endl;
}
int operator=(int a) {
cout << "In A::=" << endl;aa = a;
return a;
}
};

class B {
private:
A aa;
public:
B() {
cout << "In B::B()" << endl;
aa = 3;
}
B(int a) : aa(a) {
cout << "In B::B(int a)" << endl;
}
};

int main(int argc, char **argv, char **env) {
B b;
cout << endl;
B b2(3);
return 0;
}


[/CODE]  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 18:10 | 过客
不弄了,将就看吧,呵呵

你会发现构造的过程是:要先构造类成员变量,然后才会执行构造函数体里面的代码。

如果你把赋值代码放在函数体里,有关的数据被赋了两次值。

而基本数据类型则不需要第一次构造的过程,所以你认为过程是一样的

~~~~拍砖~~~~  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 18:25 | 过客
再解释一下哦:

在编译之后,编译器会在你的构造函数的最前面依次加上各成员变量的默认构造函数,而如果你在构造名称后指定了某些成员变量的构造参数的话,相关的项目就会被你指定的参数所代替。

在你的代码中看不出这种区别,因为int不需要构造函数(这个是C的原因,有的语言会把int初始化成0),只是在你指定时,编译器在最前面加入赋值语句。
  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 18:27 | 过客
同拍
楼上正解
因为你的是基本类型不存在构造函数  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 20:11 | greatws
谢谢各位高手的指正,是我疏忽了,只考虑了一种情况  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 22:06 | lonkil
这样的讨论方式,不错,力顶。  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的 2008-08-07 23:40 | winsty
构造函数和拷贝构造必然不同的吧……
只是因为你实验的是int这种类型……  回复  更多评论
  
# re: 今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的[未登录] 2008-08-11 10:05 | raof01
怎么可能一样?
你试试成员是其他类对象的情况看看。如A和B两个类示范的。  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理