在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。
1). 一个对象以值传递的方式传入函数体
2). 一个对象以值传递的方式从函数返回
3). 一个对象需要通过另外一个对象进行初始化搜索
拷贝构造函数与赋值运算的行为相似,用一个已存在的对象去构造一个不存在的对象(构造之前不存在),就是拷贝构造。用一个已存在的对象去覆盖另一个已存在的对象,就是赋值运算,见如下例子。
using namespace std;
class CStudent
{
public:
CStudent(char* name);
~CStudent();
CStudent(const CStudent& p);
void print();
char* _name;
CStudent& operator=(const CStudent& rhs)
{
cout <<"赋值运算"<< endl;
if (this == &rhs) {
return *this;
}
this->_name = rhs._name;
return *this;
}
private:
};
CStudent::CStudent(const CStudent& p)
{
cout << "拷贝构造函数" << endl;
_name = new char[strlen(p._name) + 1]; //深拷贝
if (_name != NULL)
strcpy_s(_name, strlen(p._name) + 1, p._name);
}
CStudent::CStudent(char* name)
{
cout << "构造函数" << endl;
_name = new char[strlen(name) + 1];
if (_name != NULL)
{
strcpy_s(_name, strlen(name)+1,name);
}
}
CStudent::~CStudent()
{
delete _name;
}
void CStudent::print()
{
cout<<_name<<endl;
}
void main()
{
CStudent stu1("tom");//调用构造函数
CStudent stu2 =stu1;//调用拷贝构造函数
CStudent stu3("jack");//调用构造函数
stu1 = stu3;//调用赋值运算
cin.get();
}
运行结果:
如果我们没有写拷贝构造函数,那么编译器会调用默认的拷贝构造函数进行浅拷贝。
浅拷贝的意思就是内存中只有一份"tom",对象stu1的name指针指向了它.把stu1拷贝给stu2后,stu2的name指向也指向了"tom",指向的是内存中同一块地址.这就会出现一个问题:当stu1的对象被销毁了,那么stu1的name指向的"tom"也会被销毁,由于stu2中的name也是指向"tom"的,所以这时stu2中的name就变成空的了,甚至是乱码。
如下例子:
class CStudent
{
public:
CStudent(char* name);
~CStudent();
void print();
char* _name;
private:
};
CStudent::CStudent(char* name)
{
_name = new char[strlen(name) + 1];
if (_name != NULL)
{
strcpy_s(_name, strlen(name)+1,name);
}
}
CStudent::~CStudent()
{
delete _name;
}
void CStudent::print()
{
cout<<_name<<endl;
}
void main()
{
CStudent stu1("tom");
CStudent stu2 =stu1;
cout << stu1._name << endl;
delete stu1._name;
cout << stu2._name << endl;
cin.get();
}
运行结果:
深拷贝是既拷贝成员,又拷贝资源的方式。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。
系统提供的默认拷贝构造函数为浅拷贝,深拷贝必须自己定义。修改拷贝构造函数,将上面的例子修改为下面的例子:
class CStudent
{
public:
CStudent(char* name);
~CStudent();
CStudent(const CStudent& p);
void print();
char* _name;
private:
};
CStudent::CStudent(const CStudent& p)//拷贝构造函数
{
_name = new char[strlen(p._name) + 1]; //深拷贝
if (_name != NULL)
strcpy_s(_name, strlen(p._name) + 1, p._name);
}
CStudent::CStudent(char* name)
{
_name = new char[strlen(name) + 1];
if (_name != NULL)
{
strcpy_s(_name, strlen(name)+1,name);
}
}
CStudent::~CStudent()
{
delete _name;
}
void CStudent::print()
{
cout<<_name<<endl;
}
void main()
{
CStudent stu1("tom");
CStudent stu2 =stu1;
cout << stu1._name << endl;
delete stu1._name;
cout << stu2._name << endl;
cin.get();
}
运行结果: