浅拷贝:简单的赋值拷贝操作(这个是系统默认提供的)
深拷贝:在堆区重新释放空间,进行拷贝操作(要自己写的)
简单来说,只要类属性里有指针等就必须利用深拷贝操作
为便于深刻理解,先看一个实例:
#include<iostream>
using namespace std;
class Person ******Person类分隔符*******
{
public:Person(){cout<<"默认构造函数的调用\n";}Person(int age){cout<<"有参构造函数的调用\n";m_age=age;} ~Person(){cout<<"析构函数的调用\n";}int m_age;
}; ******Person类分隔符*******
int main()
{Person a(10);Person b(a);cout<<"a的年龄为:"<<a.m_age<<endl;cout<<"b的年龄为:"<<b.m_age<<endl;
}
运行结果:
运行结果显然没有问题,我们在初始化类b的时候,系统调用了默认拷贝构造函数,把a中的值传递给了b;下面,我们增加类Person的一个指针属性m_height,并且把身高属性放置到堆区:
tip:堆区由程序员手动开创与释放,new出来的数据就位于堆区
#include<iostream>
using namespace std;
class Person ******Person类分隔符*******
{
public:Person(){cout<<"默认构造函数的调用\n";}Person(int age,int height){cout<<"有参构造函数的调用\n";m_age=age;m_height=new int(height); //**} ~Person(){cout<<"析构函数的调用\n";}int m_age;int* m_height;
}; ******Person类分隔符*******
int main()
{Person a(19,170);Person b(a);cout<<"a的年龄为:"<<a.m_age<<" a的身高为:"<<*a.m_height<<endl;cout<<"b的年龄为:"<<b.m_age<<" b的身高为:"<<*b.m_height<<endl;
}
运行结果为:
运行结果看起来没问题,但是代码实际上是不规范的;堆区的数据需要程序员手动开创与释放,需要用到析构函数,我们进行析构代码的完善:
~Person(){//析构代码,将堆区开辟的数据释放干净if(m_height!=NULL){delete m_height;m_height=NULL; //防止指针滞空变成野指针}cout<<"析构函数的调用\n";}
但当继续运行程序的时候会发现代码已经崩了(部分编译器现象不明显,如Dev,这里不再截图),什么原因导致的?我们分析一下:
二次释放同一块内存会被编译器视为非法操作;可知,浅拷贝带来的问题就是堆区的内存被重复释放。解决这个问题就需要利用深拷贝,具体做法便是重新开辟一个内存空间存放数据,利用深拷贝构造函数使b的指针指向新开辟的空间,这样,a与b各指向一块堆区的数据,两块空间存放的数据是一样的,这样就在拷贝的同时避免了对同一空间的重复释放问题。
具体代码实现如下:
#include<iostream>
using namespace std;
class Person *****类Person*****
{
public:Person(){cout<<"默认构造函数的调用\n";}Person(int age,int height){cout<<"有参构造函数的调用\n";m_age=age;m_height=new int(height);} Person(const Person& p){cout<<"拷贝构造函数的调用"<<endl;m_age=p.m_age;m_height=new int(*p.m_height);// <-深拷贝操作 //编译器提供的拷贝函数是:m_height=p.m_height; <-浅拷贝//由此可见浅拷贝中a,b指向的是同一块内存}~Person(){if(m_height!=NULL){delete m_height;m_height=NULL; //防止指针滞空变成野指针}cout<<"析构函数的调用\n";}int m_age;int* m_height;
}; *****类Person*****
int main()
{Person a(19,170);Person b(a);cout<<"a的年龄为:"<<a.m_age<<" a的身高为:"<<*a.m_height<<endl;cout<<"b的年龄为:"<<b.m_age<<" b的身高为:"<<*b.m_height<<endl;
}
运行结果为:
———— ———— ———— —————分割线———— ———— ———— ———— ————
下面附两张截图:
浅拷贝时两个对象height属性的地址:
深拷贝时两个对象height的地址:
如果对你有用,希望优秀的你能给作者一个小小的赞和收藏[emoji]