今天来学习一下拷贝构造函数。主要参考资料为《C++编程思想 第2版 第I卷》中第十一章节。
拷贝构造函数由引用引起的。在函数调用时,这个构造函数是控制通过传值方式传递和返回用户定义类型的根本所在。编译器在没有提供拷贝构造函数时将会自动地创建。
在C语言中的传值方式,其本质是按位拷贝参数到堆栈中的函数参数地址。有这样一个例子:
#include
<
stdio.h
>
#include < stdlib.h >
void func( int x, int y)
... {
printf("x=[%d] y=[%d] ",x,y);
}
int main( int argc, char * argv[])
... {
int a = 1;
int b = 2;
func(a, b);
system("PAUSE");
return 0;
}
#include < stdlib.h >
void func( int x, int y)
... {
printf("x=[%d] y=[%d] ",x,y);
}
int main( int argc, char * argv[])
... {
int a = 1;
int b = 2;
func(a, b);
system("PAUSE");
return 0;
}
x
=
[
1
] y
=
[
2
]
:
00401296
8B450C mov eax, dword ptr [ebp
+
0C]
//
复制最右边的参数b的值
: 00401299 89442408 mov dword ptr [esp + 08 ], eax // 复制到地址ptr[esp+08]
:0040129D 8B4508 mov eax, dword ptr [ebp + 08 ] // 复制第二个参数a的值
:004012A0 89442404 mov dword ptr [esp + 04 ], eax // 复制到地址ptr[esp+04]
:004012A4 C7042400304000 mov dword ptr [esp], 00403000
: 00401299 89442408 mov dword ptr [esp + 08 ], eax // 复制到地址ptr[esp+08]
:0040129D 8B4508 mov eax, dword ptr [ebp + 08 ] // 复制第二个参数a的值
:004012A0 89442404 mov dword ptr [esp + 04 ], eax // 复制到地址ptr[esp+04]
:004012A4 C7042400304000 mov dword ptr [esp], 00403000
这里可以看到对函数的形参作了值拷贝,并且是按位拷贝的。
我将func函数更改如下:
int
m
=
x
+
y;
:
00401296
8B450C mov eax, dword ptr [ebp
+
0C]
: 00401299 034508 add eax, dword ptr [ebp + 08 ]
:0040129C 8945FC mov dword ptr [ebp - 04 ], eax
: 00401299 034508 add eax, dword ptr [ebp + 08 ]
:0040129C 8945FC mov dword ptr [ebp - 04 ], eax
从后面的汇编代码中可以发现,这个时候并没有对参数进行拷贝,而是直接将实参进行了加法计算,只是将结果存到某一个位置。当然,也可能是自己理解有误。这个问题暂时先放着,后面再研究。
再说说按位拷贝为什么无法满足C++中传对象的要求。对于这一点,《C++编程思想》这么说的:“(但)在C++中,对象比一组比特位要复杂得多,因为对象具有含义。这个含义也许不能由它具有的位拷贝来很好地反映”。
自己再作个小结:当对对象进行按值传递时,就会调用对象的拷贝构造函数(一般情况下)。而饮用传递,其实是传递对象地址的一个副本。当在函数中对对象状态修改后,会将副本清除,但是实际的对象状态的变化不会被清除,而是保留了在函数中所作的修改。