运算符重载-赋值运算符重载
一、若想对年龄进行拷贝,写出如下代码
#include<iostream>
using namespace std;
//赋值运算符重载
class Person
{
public:
Person(int age) {
mage=new int(age);//传入一个年龄,将传入的年龄开辟到堆区,并且让mage这个指针维护堆区的数据
}
~Person()//析构函数
{
if (mage != NULL) {
delete mage;
mage = NULL;
}
}
int* mage;//设计成一个指针,年龄真实数据开辟到堆区
};
void test01() {
Person p1(18);
Person p2(20);
p2 = p1;//赋值操作,这是一种浅拷贝,会造成堆区内存重复释放,所以要用深拷贝来解决
cout << "p1的年龄为:" << *p1.mage << endl;
cout << "p2的年龄为:" << *p2.mage << endl;
}
int main() {
test01();
system("pause");
return 0;
}
代码p2=p1会产生报错,因为年龄是在堆区创建的,指针记录的是存放数据的地址,简单的浅拷贝只是让两个指针指向同一个地址,而堆区的数据是只有一份的,所以当执行析构函数的时候,p2先判断指针是否为空,不为空就释放了堆区内存,而p1也是这样,所以就会造成堆区内存的重复释放,程序崩溃
二、利用深拷贝来解决这个问题
所谓深拷贝,就是拷贝的时候在堆区重新开辟一份内存来存放数据
在类中写出重载函数,开辟多大的内存呢?比如p1中的是18,就把p1指针取内容,然后开辟所取内容那么大的内存,进行深拷贝,再运行时就发现不会崩溃了
//赋值运算符的重载
void operator=(Person &p) {
//编译器提供的是浅拷贝,如下
//mage = p.mage;
//要想实现深拷贝,得写出下面的代码
//由于在Person p2(20)时,p2已经开辟了一个堆区内存了,所以应该先判断是否有属性在堆区,如果有的话要先释放干净,然后再进行深拷贝
if (mage != NULL) {
delete mage;
mage = NULL;
}
//深拷贝
mage = new int(*p.mage);
}
运行结果如下:
三、深拷贝代码的进一步修改
上面的代码运行之后已经不报错了,但是其实还有问题,就是我们无法实现p3=p2=p1
比如我们把test01写成下面这种,就无法实现拷贝
void test01() {
Person p1(18);
Person p2(20);
Person p3(30);
p3 = p2 = p1;
cout << "p1的年龄为:" << *p1.mage << endl;
cout << "p2的年龄为:" << *p2.mage << endl;
cout << "p3的年龄为:" << *p3.mage << endl;
}
此时p3 = p2 = p1会提示:
C++ 没有与这些操作数匹配的 运算符 操作数类型为: Person = void
这是因为那个重载函数返回的是void型,那句话相当于是p3=void,肯定是不行的,那么要怎么修改呢?就是修改一下重载函数,要返回对象自身。怎么返回自身?用this
//赋值运算符的重载
Person& operator=(Person &p) {//返回一个引用
//编译器提供的是浅拷贝,如下
//mage = p.mage;
//要想实现深拷贝,得写出下面的代码
//由于在Person p2(20)时,p2已经开辟了一个堆区内存了,所以应该先判断是否有属性在堆区,如果有的话要先释放干净,然后再进行深拷贝
if (mage != NULL) {
delete mage;
mage = NULL;
}
//深拷贝
mage = new int(*p.mage);
//返回对象本身
return *this;
}
int* mage;//设计成一个指针,年龄真实数据开辟到堆区
};
此时代码运行结果如下:
可见,已经赋值成功