1、定义
拷贝构造函数是一种特殊的构造函数,函数的名称和类名称相同,拷贝构造函数的参数必须有一个是本类型的一个引用。
2、用的场景
(1)类的对象以值传递的方式传入函数的参数;
例子
class A{
public:
A(int a){
cout << "构造函数执行" << endl;
}
A(A &temp){
c = temp.c;
cout << "拷贝构造函数执行" << endl;
}
~A(){
cout << "析构函数执行"<<endl;
}
private:
int c;
};
void fun(A temp)
{
cout << "fun函数已经执行" <<endl;
}
int main()
{
A test(2);
fun(test);
return 0;
}
上例子中当调用fun()函数的时候就会调用拷贝构造函数。
第一步先把test传给形参temp(传值时会临时生成一个A类型的temp) ,这时调用了构造函数
第二部当fun函数执行完时,调用析构 函数,析构C;
(2)类对象以函数返回值的形式进行返回(该种方法我用devC++编写的时候没有执行该构造函数,VS2013可以)
(3)类的对象需要用另一个类的函数进行初始化;
A c(3);
A b = c;
2、浅拷贝和深拷贝的理解
(1)默认构造函数
当个人没有显示得定义拷贝构造函数的时候,当出现上述用到拷贝构造函数的时候,编译器会自动的产生一个拷贝构造函数,但是这个构造函数完成的功能有限,只是通过“老”对象的数据成员的值对“新”成员进行赋值操作。
(2)浅拷贝
浅拷贝就是对象在复制的时候,支队对象中的数据成员进行简单的赋值,默认构造函数就是浅拷贝。一般浅拷贝就已经够用了,但是对象存在一些动态的成员的时候浅拷贝就不行了。下例就是浅拷贝不行的时候。
class Rect
{
public:
Rect() // 构造函数,p指向堆中分配的一空间
{
p = new int(100);
}
~Rect() // 析构函数,释放动态分配的空间
{
if(p != NULL)
{
delete p;
}
}
private:
int width;
int height;
int *p; // 一指针成员
};
int main()
{
Rect rect1;
Rect rect2(rect1); // 复制对象
return 0;
}
在这段代码运行结束之前,会出现一个运行错误。原因就在于在进行对象复制时,对于动态分 配的内容没有进行正确的操作。我们来分析一下:
在运行定义rect1对象后,由于在构造函数中有一个动态分配的语句,因此执行后的内存情况大致如下:
在使用rect1复制rect2时,由于执行的是浅拷贝,只是将成员的值进行赋值,这时rect1.p = rect2.p,也即这两个指针指向了堆里的同一个空间,如下图所示:
当然,这不是我们所期望的结果,在销毁对象时,两个对象的析构函数将对同一个内存空间释放两次,这就是错误出现的原因。我们需要的不是两个p有相同的值,而是两个p指向的空间有相同的值,解决办法就是使用“深拷贝”。
(3)深拷贝
在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空间,如上面的例子就应该按照如下的方式进行处理
class Rect
{
public:
Rect() // 构造函数,p指向堆中分配的一空间
{
p = new int(100);
}
Rect(const Rect& r)
{
width = r.width;
height = r.height;
p = new int; // 为新对象重新动态分配空间
*p = *(r.p);
}
~Rect() // 析构函数,释放动态分配的空间
{
if(p != NULL)
{
delete p;
}
}
private:
int width;
int height;
int *p; // 一指针成员
};
此时,在完成对象的复制后,内存的一个大致情况如下:
此时rect1的p和rect2的p各自指向一段内存空间,但它们指向的空间具有相同的内容,这就是所谓的“深拷贝”。
(注释:浅、深拷贝摘自http://www.baidu.com/link?url=tOZti-L4j-cCNlEWYHoOyKJqANdXP6obJY9RWafaZ4QHXzeq8hLSRUSWzoGz4cwIlY4JbtFkl9nDVGZJEvmh0_&wd=&eqid=92f6a11a001c0b8500000003572d9a6a)注意:一个类中可以有多个拷贝构造函数。根据参数的不同区调用不同的构造函数。