1、拷贝构造函数
先看个简单的例子:
#include<iostream>
using namespace std
class Test{
public:
Test(int b)
{
a=b;
}
void print()
{
cout<<a<<endl;
}
private:
int a;
};
int main()
{
Test obj(100);
Test obj1=obj;
obj1.print();
return 0;
}
运行结果为100。从代码可以看出,系统为对象obj1分配了内存并完成了与对象obj的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
当用一个已经初始化过的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的对象需要拷贝时,可拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:
1、一个对象以值传递的方式传入函数体;
2、一个对象以值传递的方式从函数返回;
3、一个对象需要通过另外一个对象进行初始化;
如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝。
自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。自定义拷贝构造函数示列:
Test(const Test& obj2)
{
a=obj2.a;
}
2、深拷贝和浅拷贝
在某些情况下(如果类中包含了指针),类内成员变量需要动态开辟堆内存,如果实行位拷贝(即浅拷贝),也就是把对象里的值完全复制给另一个对象,如obj1=obj,这时,如果obj中有一个成员变量指针已经申请了内存,那obj1中的那个成员变量也指向同一块内存。这就出现一个问题:当把obj内存释放了(如析构),这时obj1内的指针就是野指针了,出现运行错误。
为了解决这个问题,我们可以采用深拷贝方式,就是对资源进行重新分配,如下示列:
#include <iostream>
using namespace std;
class Test
{
public:
Test(int b,char* cstr)
{
a=b;
str=new char[b];
strcpy(str,cstr);
}
Test(const Test& C)
{
a=C.a;
str=new char[a]; //对资源进行性分配,深拷贝
if(str!=0)
strcpy(str,C.str);
}
void Show()
{
cout<<str<<endl;
}
~Test()
{
delete str;
}
private:
int a;
char *str;
};
int main()
{
Test A(10,"Hello!");
Test B=A;
B.Show();
return 0;
}
所谓的深拷贝,就是说所有的对象都是重复的,即将A的值拷贝到B中,B会将A的值复制一份放在内存中,不管A做如何改变,B始终是A刚开始拷贝的值,但它们所指向的内存地址是不一样的。
3、总结
浅拷贝就是对象的数据成员之间的简单复制。如果设计一个类而没有自定义拷贝构造函数,当用一个对象去给另一个对象赋值所执行的过程就是浅拷贝;
如果对象中没有其他的资源(如堆,文件,系统资源等)时,深拷贝和浅拷贝没有什么区别。但是如果对象中有动态分配内存的成员变量时,就需要深拷贝了,需要另外开辟一块新的资源进行复制。
深拷贝和浅拷贝的区别是在对象状态中包含其它对象的引用的时候,当拷贝一个对象时,如果需要拷贝这个对象引用的对象,则是深拷贝,否则是浅拷贝。
浅拷贝就是对对象成员简单的复制,复制后的成员变量所指向的内存地址是相同的,而深拷贝是在内存中重新开辟一个空间来存放原来对象的成员变量,其内存地址是不同的。