【C++要笑着学】运算符重载 | 赋值重载 | 取地址重载 | const成员
写在前面:
本章将开始讲解运算符重载。运算符重载的技能是学习实现 STL 内部底层的不可缺少的 "利器" !所以本篇非常重要,下一篇会手把手实现一个Date类,可以进一步地实战体会运算符重载。
Ⅰ. 运算符重载
0x00 引入
什么是运算符重载呢?
C++ 为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
简单来说:就是能让自定义类型和内置类型一样使用运算符。
0x01 运算符重载的概念
函数名: 关键字 operator+ 需要重载的运算符符号
函数原型:返回值类型 operator 操作符(参数列表)
返回值类型,看操作符运算后返回的值是什么。
参数,操作符有几个操作数,它就有几个参数。
📌 注意事项:
① 不能通过连接其他符号来创建新的操作符,
你只能对已有的运算符进行重载,你也不能对内置类型进行重载。
② 重载操作符必须有一个类类型或枚举类型的操作数。
③ 用于内置类型的操作符,其含义不能改变。比如内置的 整型 +,你不能改变其含义。
④ 作为类成员的重载函数时,其形参看起来比操作数数目少 1,
成员函数的操作符有一个默认的形参 this,限定为第一个形参。
⑤ 不支持运算符重载的 5 个运算符:
虽然点运算符( . )不能重载,但是箭头运算符( -> )是支持重载的
解引用(*)是可以重载的,不能重载的是点星运算符( .* )
⑥ 会自动转化
重载后的运算符可以直接用!岂不美哉?
💬 举一个运算符重载的例子: ==
🚩 运行结果演示:
这里会发现运算符重载成全局的,我们不得不将成员变量是共有的,
我们得把 private 撤掉:
❓ 那么问题来了,封装性如何保证?
这里其实可以用 "友元" 来解决,如果现在不知道也没关系,我们后面会讲。
💬 或者干脆直接重载成成员函数就完事儿了:
🔑 解读:
既然要当成员函数,就得明白这里的 this 指的是谁。
需要注意的是,左操作数是 this 指向的调用函数的对象。
此外,因为前几章才讲 this 指针,为了演示清楚,所以我这里把 this 写上(虽然可以不写)。
Ⅱ. 赋值重载(默认成员函数)
0x00 概念
赋值重载主要是把一个对象赋值给另一个对象。
如果你不写,编译器会默认生成。
0x02 operator=(默认成员函数)
📌 要分清!
类的默认成员函数 —— 赋值重载
赋值运算符重载主要有以下四点:
① 参数类型
② 返回值年
③ 检查是否给自己复制
④ 返回 *this
💬 d1 = d2
🔑 解读:
一定要防止自己和自己赋值!我们这里加 if 语句来判断就是为了防止极端情况下,
自己给自己赋值,加上这条判断后就算遇到自己给自己赋值,就会不做处理,直接跳过。
*this 还在,所以我们可以使用引用来减少拷贝。
因为出了作用域💬 我们来验证一下:
① 我们先把引用返回去掉:
② 这里为了方便观察,就不让拷贝构造函数自己生成了。
我们自己实现一个只会嗷嗷叫的拷贝构造函数,不让编译器自己生成。
🚩 运行结果如下:
我们发现,调用了三次拷贝构造函数。
🔍 我们来调试看一下:
① 第一句 "调用了一次拷贝构造" 是因为 Date d4(d3) ,我们自己调用的。
② 第二句出自 d1 = d2 = d3 ,先是 d2 = d3。
因为传值返回不会直接返回对象,而是会生成一个拷贝的对象。
③ 第三句是 d2 = d3 搞完后把返回值作为参数再去调用:
所以一共三次:
💬 我们这里出了作用域,对象还在,就可以使用引用返回:
🚩 运行结果如下:
成功减少了拷贝!
📚 赋值运算符重载是默认成员函数,所以如果一个类没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝。
既然编译器会自己默认生成,已经可以完成字节序的值拷贝了,我们还需要自己实现吗?
(上一篇博客我们经常问这种问题,以后就不再多说了)
当然像日期这样的类是没有必要的,有时候还是需要自己实现的。
💬 比如下面这种情况:
📌 编译器默认生成复制重载,跟拷贝构造做的事情完全类似:
① 内置类型成员,会完成字节序值拷贝 —— 浅拷贝。
② 对于自定义类型成员变量,会调用它的 operator= 赋值。
Ⅲ. const 成员
0x00 引入
Print ,是可以调得动的。
我们定义一个日期类,对它调用
❓ 如果我这个对象是 const 的呢?
这样编译就报错了,这块报错的原因是什么?
这里涉及的问题是 "权限的放大" ,这个知识点我们再前几章讲过。
我们可以使用 const 成员函数来解决这种情况,我们继续往下看。
0x01 const 修饰类的成员函数
将 const 修饰的类成员函数,我们称之为 const 成员函数。
const 修饰类成员函数,实际修饰的是该成员函数隐含的 this 指针,
表明在该成员函数中不能对类的任何成员进行修改。
💬 这里我们可以在函数后面加 const,保持权限的统一:
🔑 直接看图详解:
为了能够更好地展示出 this 指针传递和接收的过程,我用黑色代码块表示。
0x02 使用建议
const 是很好的!
成员函数加建议能加上 const 都加上,这样普通对象和 const 对象都可以调用了。
但是,如果要修改成员变量的成员函数是不能加的,比如日期类中 += ++ 等等实现。
它是要修改的,你加 const 还怎么修改成员变量??直接让它爬!
(因为加 const,指向的类容不可被修改)
Ⅳ. 取地址重载(默认成员函数)
0x00 取地址操作符重载
💬 取地址运算符重载也是一个默认成员函数。
🚩 运行结果如下:
0x01 const 取地址运算符重载
💬 const 取地址运算符重载:
🚩 运行结果:
0x02 建议
这两个运算符一般不需要重载。
因为它是默认成员函数,编译器会自己默认生成。
💬 其实让编译器自己去生成,就够 了:
🚩 运行结果:
💬 只有特殊情况才需要重载,比如你不想让别人取到你的地址:
🚩 运行结果:
参考资料:
Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .
百度百科[EB/OL]. []. https://baike.baidu.com/.
比特科技. C++[EB/OL]. 2021[2021.8.31].
- 点赞
- 收藏
- 关注作者
评论(0)