复制(拷贝)构造函数
- 用法
- 详解
1、用法
所有需要分配系统资源的用户定义的类型都需要一个复制构造函数。所以在定义类的时候,是会自动的生成默认的复制构造函数的。复制构造函数是在建立对象时可用同一类的另一个对象来初始化该对象。同一个类的对象在内存中具有完全相同的结构,如果作为一个整体进行复杂是完全可行的,这个复制过程只需要复制数据成员,而函数成员是共用的(没有复杂)。
主要有以下常见的用法:
1、对象在创建时使用其他的对象初始化
Person p(q); //此时复制构造函数被用来创建实例p
Person p = q; //此时复制构造函数被用来在定义实例p时初始化p
2、对象作为函数的参数进行值传递时
f(p); //此时p作为函数的参数进行值传递,p入栈时会调用复制构造函数创建一个局部对象,与函数内的局部变量具有相同的作用域
需要注意的是,赋值并不会调用复制构造函数,赋值只是赋值运算符(重载)在起作用
p = q; //此时没有复制构造函数的调用!
简单来记的话就是,如果对象在声明的同时将另一个已存在的对象赋给它,就会调用复制构造函数;如果对象已经存在,然后将另一个已存在的对象赋给它,调用的就是赋值运算符(重载)。
默认的复制构造函数和赋值运算符进行的都是”shallow copy”,只是简单地复制字段,因此如果对象中含有动态分配的内存,就需要我们自己重写复制构造函数或者重载赋值运算符来实现”deep copy”,确保数据的完整性和安全性。
2、详解
下面进行演示对象在使用复制构造函数的创建和撤销的过程:
#include<iostream>
using namespace std;
class complex{
private:
double real, image;
public:
complex(){
real = 0.0;
image = 0.0;
cout << "Initializing 0 0" << endl;
}
complex(double r, double i=0.0){
real = r;
image = i;
cout << "initializing" << r <<'\t' << i <<endl;
}
complex(complex &com);
~complex(){
cout << "Destruction" << endl;
}
void assign(complex com){
real = com.real;
image = com.image;
}
void print(){
cout << real <<'+'<< image << 'i' << endl;
}
};
inline complex::complex(complex &com){
cout << "Copy" << com.real << '\t' << com.image << endl;
real = com.real;
image = com.image;
}
complex fun(complex);
complex global;
int main(int argc, _TCHAR* argv[])
{
cout << "Entering main" << endl;
complex com1, com2(5.6, 7.5);
complex com3 = com1;
com3.print();
global.print();
com1 = fun(com2);
com1.print();
cout << "Exiting main" << endl;
return 0;
}
complex fun(complex com)
{
cout << "Entering function" << endl;
global.assign(com);
cout << "Exiting function" << endl;
return global;
}
下面对程序运行过程进行分析:
1、Initializing 0 0 // 全局对象首先建立,调用默认的构造函数
2、Entering main // 进入入口函数
3、Initializing 0 0 // 调用默认的构造函数建立com1
4、Initializing 5.6 7.5 // 调用带参数的构造函数建立com2
5、Copy 0 0 // 调用复制构造函数建立com3
6、0+0i // 打印com3
7、0+0i // 打印global
8、Copy 5.6 7.5 // 调用全局函数fun(),调用复制构造函数建立临时对象com
9、Entering function // 进入全局函数fun()
10、Copy 5.6 7.5 // 进入global.assign(),调用复制构造函数建立临时新对象com
11、Destructor //退出global.assign(),调用析构函数,撤销新com
12、Exiting function // 退出全局函数fun()
13、Copy 5.6 7.5 // 返回对象时,调用复制构造函数建立临时对象
14、Destructor //退出fun(),调用析构函数,撤销fun()的com
15、Destructor // 返回的临时对象,赋给com1后析构
16、5.6+7.5i // 打印com1
17、Exist main // 退出入口函数
18、Destructor // 退出入口函数前,调用析构函数,撤销com3
19、Destructor // 退出入口函数前,调用析构函数,撤销com2
20、Destructor // 退出入口函数前,调用析构函数,撤销com1
21、Destructor // 退出入口函数前,调用析构函数,撤销global
注意:在涉及到值传递(函数参数,函数返回)时,系统都会自动的产生一个无名的临时变量来保存需要传递的值。