面向对象的编程——拷贝构造函数(2)
在C++中,一个类对象需要通过另一个类对象进行初始化、在函数调用的时候一个类对象进行值传递入函数和返回时会调用拷贝构造函数,在没有自定义拷贝构造函数的时候,编译器会产生一个默认的拷贝构造函数,但是,这样做是很危险的。这是因为浅拷贝和深拷贝的原因。
下面我们来看个例子:
#include <iostream>
using namespace std;
class CA
{
public:
CA(int b,char* cstr)
{
a=b;
str=new char[b];
strcpy(str,cstr);
}
CA(const CA& C)
{
a=C.a;
str=new char[a]; //深拷贝
if(str!=0)
strcpy(str,C.str);
}
void Show()
{
cout<<str<<endl;
}
~CA()
{
delete str;
}
private:
int a;
char *str;
};
int main()
{
CA A(10,"Hello!");
CA B=A;
B.Show();
return 0;
}
程序很简单,就用用类对象A来初始化类对象B,打印类对象B中的成员*str,程序运行结果如下:
这时候如果我们去掉自定义的拷贝构造函数CA(const CA& C),看看会发生什么事情!
出现了错误,这是为什么呢?
是这样的,在上面程序里面,我们自定义了一个析构函数,在这个函数里面,我们释放了指针str,这时候A的成员没有问题,但是,通过默认拷贝构造函数后类对象B的成员*str事实上也指向了A的成员*str所指向的地址,我们可以通过单步执行来查看两个类对象的str地址:
可以看到,两个都指向了0x000310d0.这时候,一旦你释放了str之后,这时候就会出现资源归属不清而导致错误。而当自定义了拷贝构造函数,并在拷贝构造函数中重新分配资源,那么就不会出现问题,如本例开头的程序所示,我们看下A、B类对象中str的地址:
可以看到已经为类对象B中的str重新分配了资源。
以上两种自定义和默认拷贝构造函数的情况分别对应了深拷贝和浅拷贝。所以,深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。