持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情
1️⃣前言
今天的笔记内容是:
- 赋值运算符的重载
在C++中,赋值运算符的使用很多,我们可以将类的对象A赋值给另一个对象B,相当于对象B拷贝了该类对象A的所有数据。
因此,我们自定义的类也应该有赋值运算。
与拷贝构造一样,C++编译器也会默认提供赋值运算符。
但我们要区别拷贝构造函数与赋值运算符的区别!
比如我们定义了一个类:myClass
然后操作如下:
拷贝构造函数起到一个初始化的作用。
当类对象已经存在时,使用赋值运算符可以进行赋值操作。
我们之前在学到拷贝构造函数时,提到浅拷贝和深拷贝的问题。
同样的,当值复制解决不了问题时(即浅拷贝不合适时),我们应该提供赋值运算符的重载。
2️⃣赋值运算符重载
示例
#include <iostream>
#pragma warning (disable: 4996)
using namespace std;
class Person {
public:
//无参构造函数
Person() {
m_name = nullptr;
}
//有参构造函数
Person(const char* p) {
copyName(p);
}
//拷贝构造函数
Person(Person& m) {
copyName(m.m_name);
}
//析构函数
~Person() {
deleteName();
}
//赋值运算符的重载
Person& operator=(Person& m) {
deleteName();
copyName(m.m_name);
return *this;
}
//输出类对象的名字
void show() {
if (this->m_name)
cout << "名字为:" << m_name << endl;
else
cout << "对象无名字!" << endl;
}
protected:
char* m_name;
void copyName(const char* p);
void deleteName();
};
void Person::copyName(const char* p)
{
m_name = new char[strlen(p) + 1];
if (m_name) {
strcpy(m_name, p);
}
}
void Person::deleteName()
{
if (m_name) {
delete m_name;
m_name = nullptr;
}
}
int main() {
Person x("张三");
cout << "x";
x.show();
Person y;
cout << "y";
y.show();
y = x; //赋值操作
cout << "y";
y.show();
return 0;
}
运行结果为:
解析
首先可以看到,Person类的构造函数是在堆中申请,分配空间来存储人的名字的。
那么这个时候就存在浅拷贝的问题。
因此我们需要自定义拷贝构造函数和赋值运算符的重载函数。
如上所示,重载的函数名是operator=,返回值是类对象的引用,而参数也是类对象的引用。
在函数体中,有三部分:
- 第一部分和析构函数类似,先将对象占用的资源释放掉
- 接着是重新分配新的空间资源,这与拷贝构造函数类似
- 最后返回类对象的引用
有个点注意一下:
- 问题:为什么拷贝构造函数不需要调用
deleteName()? - 解析:因为对象刚创建时,并没有分配存放名字的堆资源
3️⃣写在最后
好了,今天的笔记就到这里,欢迎大家到评论区一起讨论!