浅复制(浅克隆)
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深复制(深克隆)
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。下面举个深拷贝例子:
#include<iostream>
using namespace std;
class Student
{
private:
char *name;
public:
Student();
~Student();
void set(const char* name1)
{
if(strlen(name1)+1<256)
{
strcpy(name,name1);
}
}
// Student(const Student &p);
void print();
};
Student::Student()
{
name=new char[256];
cout<<"构造函数被调用"<<endl;
}
Student::~Student()
{
delete[] name;
cout<<"析构函数被调用"<<endl;
}
/*
Student::Student(const Student &p)
{
name=new char[256]; //默认的是 this->name=p.name
strcpy(name,p.name);
}
*/
void Student::print()
{
cout<<name<<endl;
}
int main()
{
Student p1;
p1.set("Studnet a");
p1.print();
Student p2(p1);
p2.set("Student b");
p2.print();
p1.print();
return 0;
}
在上面代码中,如果不重新定义复制构造函数则会发生内存报错,其原因在于默认的复制构造函数中是这样的this->name=p.name,这样p1的指针就指向了p2,当然原来的p1所指向的内容就丢失了,在析构的时候对指向同一块内存的指针释放了两次,当然就会报错啦。
例二:
#include<iostream>
using namespace std;
class Student
{
private:
char *name;
public:
Student(const char *pName="NO Name")
{
name=new char[strlen(pName)+1];
strcpy(name,pName);
}
void UpperName()
{
strupr(name);
}
void show()const
{
cout<<name<<endl;
}
~Student()
{
if(name != NULL)
{
delete[] name;
}
}
/* Student(Student &p)
{
name=new char[strlen(p.name)+1];
strcpy(name,p.name);
}
*/
};
int main()
{
char str[10]="Student a",*ptr=new char[10];
strcpy(ptr,"Student b");
Student p1(str),p2(ptr),p3("Student c");
p1.show();
p2.show();
p3.show();
cout<<"-------------"<<endl;
strcpy(str,"Studnt c"); //这个修改不影响对象p1
p1.show();
delete[] ptr; //这个释放不影响p2
p2.show();
p3.UpperName(); //对象属性的修改由对象自己作主
p3.show();
Student p4=p1;
p4.show();
p4.UpperName();
p4.show();
p1.show(); //出问题,pn1内容改变,并且内存报错,重载复制构造函数 Student(Student &p)
return 0;
}