浅拷贝:简单的赋值拷贝操作
举一个简单的例子:
class Person
{
public:
int age = 0;
//无参构造函数
Person()
{
cout << "调用无参构造函数" << endl;
}
//有参构造函数
Person(int a)
{
age = ;
cout << "调用有参构造函数" << endl;
}
};
int main()
{
Person p1(18);
cout << p1.age << endl;
Person p2(p1); //p2的数据由p1拷贝过去
cout << p2.age << endl;
}
运行结果为:
调用有参构造函数
18
18
在以上代码中我们没有手动写出拷贝构造函数,于是编译器会使用默认拷贝构造函数为p2赋值,对p1的数据进行了简单的复制,传给p2,即浅拷贝。
接着我们对以上代码进行修改,添加一个指针成员,这次我们要使用堆区的内存:
class Person
{
public:
int age = 0;
int * p_height = nullptr;//新增一个指针,指向堆区数据
//无参构造函数
Person()
{
cout << "调用无参构造函数" << endl;
}
//有参构造函数
Person(int a,int height)
{
age = a;
//用传进来的参数值new一个int变量,并用p_height指向它
p_height=new int(height);
cout << "调用有参构造函数" << endl;
}
};
int main()
{
Person p1(18,178);
cout << "年龄:" << p1.age << ";身高:" << *p1.p_height<< endl;
Person p2(p1);
cout << "年龄:" << p2.age << ";身高:" << *p2.p_height<< endl;
}
运行结果为:
调用有参构造函数
年龄:18;身高:178
年龄:18;身高:178
我们注意到堆区内存没有进行手动的释放,于是给上面代码添加一个析构函数:
~Person()
{
//释放堆区数据
if(p_height != nullptr)
{
delete p_height;//释放堆区数据
p_height = nullptr; //防止野指针
}
cout << "调用析构函数" << endl;
}
修改后再运行程序则会崩溃,原因是浅拷贝只是简单的复制,p1和p2的p_height指针指向的是同一块内存,p2在调用析构函数时,就将堆区开辟的空间释放了,所以之后p1执行析构函数就找不到要释放的堆区数据,造成程序崩溃。
深拷贝:在堆区重新申请空间,进行拷贝操作
为了实现深拷贝,我们需要手动写一个拷贝构造函数:
Person(const Person & p)
{
cout << "调用拷贝构造函数" << endl;
age = p.age;
//深拷贝操作:在堆区再申请一块新内存给新指针
this.p_height=new int(*p.p_height);//解引用出原指针的值
//如果是默认构造函数,则只会简单的复制:
//this.p_height=p.p_height;
}
如此一来,p1和p2的p_height指针就会分别指向不同的内存。