前言:拷贝顾名思义就是复制。我们在函数调用时,如果使用的是值传递的方式,采用的就是浅拷贝,就是简单的复制。如果使用的是按引用传递或者指针传递的话,就是深拷贝。下面我们来介绍这两种拷贝的异同。
1.作用
举一个例子来说明其作用。我们首先用有参构造函数构造一个对象p,其有两个属性,一个m_Age,一个m_Height.当p.m_Height初始化时候,是用new关键词在堆区开辟了一个空间来存放(有new开辟,就需要用delete释放)。
此时当使用系统自动创建的拷贝构造函数去初始化一个新对象时,对于p.m_Height参数使用浅拷贝的操作,即把p.m_Height指向的地址给复制了一份,然后给了p1.m_Height,此时没什么问题,但是别忘了在调用结束后还会有析构函数,去对在堆区开辟的内存进行释放。我们用了一次有参构造,一次拷贝构造,所以析构函数会进行两次,会对同一块内存释放两次,这是非法的。接下来我们提出解决办法。
//这段代码用来说明系统创建的析构函数,即对堆区空间进行浅拷贝会引发的错误
#include<iostream>
using namespace std;
class Person
{
public:
Person()
{
}
Person(int age, int high)
{
m_Age = age;
m_Height = new int(high);
}
Person(const Person& p)
{
m_Age = p.m_Age;
m_Height = p.m_Height;
}
~Person()
{
if (m_Height != NULL)
{
delete m_Height;
m_Height = NULL;
}
}
int* m_Height;
int m_Age;
};
void test1() {
Person p(29,160);
Person p1(p); //用系统的拷贝构造函数,此时为浅拷贝
}
int main()
{
test1();
system("pause");
return 0;
}
我们需要修改系统给的拷贝构造函数,在这个函数中,我们需要在堆区创建一个新的空间,用来放p1.m_Height,这样p和p1的m_Height不会指向同一片空间,带来的好处就是在释放时不会出现释放同一片空间两次的情况。
//拷贝构造函数的修改:
Person(const Person& p)
{
m_Age = p.m_Age;
m_Height = new int(*p.m_Height);//在堆区开辟空间
}
2.定义
浅拷贝:简单的赋值操作
深拷贝:在堆区重新申请空间,进行拷贝操作
3.注意事项
1.如果成员属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题。
2.需要在析构函数进行释放堆区空间的操作