1.出现拷贝构造函数的原因:
出现类的等号赋值时,会调用拷贝构造函数
默认拷贝构造---浅拷贝
值之间的拷贝,如果有指针作为数据成员,则会导致两个对象的指针指向同一段内存单元那么在析构的时候会出问题
深拷贝
如果有指针作为数据成员,而且用本类的旧对象去构造了新对象,则要写拷贝构造给新对象的指针要去开辟和旧对象指针同样大小的内存单元,然后拷贝相同的值
不但拷贝值,而且要拷贝资源
2.出现深拷贝的原因:
当数据成员中含有指针时,必须用深拷贝
在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的;但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,(拷贝构造的对象先析构,旧对象指向的地址已经被释放)而导致指针悬挂现象,所以,此时,必须采用深拷贝(拷贝构造给新对象的指针要去开辟和旧对象指针同样大小的内存单元,然后拷贝相同的值)。
3.代码:
浅拷贝:
class Student
{
public:
Student(int num = 0, const char* name = "oo", char sex = 'm') :m_num(num), m_sex(sex)
{
cout << "构造" << endl;
m_name = new char[strlen(name) + 1];
strcpy(m_name, name);
}
Student(const Student& s) :m_num(s.m_num), m_sex(s.m_sex) //浅拷贝
{
cout << "浅拷贝" << endl;
}
~Student()
{
cout << "析构" << endl;
delete[]m_name;
}
void Print()
{
cout << m_num << " " << m_name << " " << m_sex << endl;
}
private:
int m_num;
char* m_name;
char m_sex;
};
void main()
{
Student s(1001, "list", 'f');
s.Print();
Student s1(s);//调用默认拷贝构造 ,导致s1对象中的m_name和s对象中的m_name指向的内存相同//浅拷贝
s1.Print();
}
1.先调用构造函数,构造s对象
2.打印s对象
3.调用深拷贝,构造s1对象
4.打印s1对象
调用默认拷贝构造 ,导致s1对象中的m_name和s对象中的m_name指向的内存相同
这里的s1(s)执行的是一个浅拷贝过程。我说过浅拷贝是对象数据之间的简单赋值,比如:
s1.size = s.size;
s1.data = s.data;
这里s1的指针data和s的指针指向了堆上的同一块内存,s和s1析构时,s1先把其data指向的动态分配的内存释放了一次,而后s析构时又将这块已经被释放过的内存再释放一次。对同一块动态内存执行2次以上释放的结果是未定义的,所以这将导致内存泄露或程序崩溃。
所以这里就需要深拷贝来解决这个问题,深拷贝指的就是当拷贝对象中有对其他资源(如堆、文件、系统等)的引用时(引用可以是指针或引用)时,对象的另开辟一块新的资源,而不再对拷贝对象中有对其他资源的引用的指针或引用进行单纯的赋值。
深拷贝:
class Student
{
public:
Student(int num = 0, const char* name = "oo", char sex = 'm') :m_num(num), m_sex(sex)
{
cout << "构造" << endl;
m_name = new char[strlen(name) + 1];
strcpy(m_name, name);
}
Student(const Student& s) :m_num(s.m_num), m_sex(s.m_sex) //深拷贝
{
cout << "深拷贝" << endl;
m_name = new char[strlen(s.m_name) + 1];//开辟和旧对象的字符串一样大小的内存
strcpy(m_name, s.m_name);
}
~Student()
{
cout << "析构" << endl;
delete[]m_name;
}
void Print()
{
cout << m_num << " " << m_name << " " << m_sex << endl;
}
private:
int m_num;
char* m_name;
char m_sex;
};
void main()
{
Student s(1001, "list", 'f');
s.Print();
Student s1(s);//调用深拷贝,拷贝值,而且要拷贝资源
s1.Print();
}
1.先调用构造函数,构造s对象
2.打印s对象
3.调用深拷贝,构造s1对象
4.打印s1对象
5.析构s1对象
6.析构s对象
拷贝了一个一模一样的资源
总结:深拷贝和浅拷贝的区别是在对象状态中包含其它对象的引用的时候,当拷贝一个对象时,如果需要拷贝这个对象引用的对象,则是深拷贝,否则是浅拷贝。
4.区别:
深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了指针悬挂的问题。
浅拷贝(默认拷贝函数):将原对象或原数组的引用直接赋给新对象,新数组,新对象/新数组只是原对象的一个引用。
深拷贝:创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是引用
深拷贝会在堆内存中另外申请空间来储存数据,从而解决了指针悬挂问题。