《Beginning C++20 From Novice to Professional》第十三章 Operator Overloading
操作符重载主要是让自定义类型有和内置类型类似的自然的操作,比如字符串的连接、矩阵的运算等等用操作符比使用成员函数(虽然也是成员函数)要直观一些
本章我们可以学到:
Implementing Operators for a Class
上一章我们实现的Truckload类有一个寻找最大体积的函数,其中有段逻辑是这样的:
比较两个数我们会自然地想到数学里的<>=运算符,而不是使用成员函数compare然后拿返回值和0比较,所以能不能写成下面这样的形式呢?
再比如两个盒子体积相加、相乘等类数学运算操作,如果写成数学表达式的形式会更有可读性
Operator Overloading 操作符重载
实际上string类里就有很多重载的操作符,比如+用来连接两个string,或者==来判断两个字符串是否相同,如果像这样设计的好,操作符重载可以让我们不加思考地写出非常优雅的代码
操作符函数本身也是函数,和普通函数不一样的地方在于,我们实现自己的版本时需要加上operator这个关键字
Implementing an Overloaded Operator
让我们来看个例子:
因为是比较,所以小于操作符函数的返回类型应该是bool;这里参数表示的是操作符的第二个操作对象,假如a<b,那么相当于a.operator<(b),a是调用这个成员操作符函数的对象,b就是这个函数的参数;const不多说了,比较操作应该对对象数据是只读的
然后用了这个形式(先不管实现),我们就可以写成下面的比较
书中也提供了一幅图来说明上面的过程,还提供了实现(就一行)
下面代码用来验证重载的比较操作
注意我们的smallBox是用来存储最大值的对象,在循环过程中只要发现有比之前大的就重新赋值,这里的=其实也是一个操作符,但是我们并没有实现,因为编译器默认给所有类生成一个赋值运算符函数,把右侧对象给复制到左边,行为就像复制构造函数
但是这个默认赋值操作有时候并不能完全满足实际需要,后面的小节里我们会说到这个问题
Nonmember Operator Functions
#include <iostream>
#include <vector>
using namespace std;
class Box {
public:
// Constructors
Box() = default;
Box(double l, double w, double h) : m_length{l}, m_width{w}, m_height{h} {}
double volume() const { return m_length * m_width * m_height; }
// Accessors
double getLength() const { return m_length; }
double getWidth() const { return m_width; }
double getHeight() const { return m_height; }
private:
double m_length{1.0};
double m_width{1.0};
double m_height{1.0};
};
bool operator<(const Box& box1, const Box& box2) { return box1.volume() < box2.volume(); }
int main() {
std::vector boxes{Box{2.0, 2.0, 3.0},
Box{1.0, 3.0, 2.0},
Box{1.0, 2.0, 1.0},
Box{2.0, 3.0, 3.0}
};
Box smallBox{boxes[0]};
for (const auto& box: boxes) {
if (box < smallBox)
smallBox = box;
}
std::cout << "The smallest box has dimensions "
<< smallBox.getLength() << 'x'
<< smallBox.getWidth() << 'x'
<< smallBox.getHeight() << std::endl;
}
对于<这样的两元运算符,一般还是重