← 目录 / 第十二章 · 类与面向对象 / 12.5 运算符重载

12.5 运算符重载

让你自己定义的类型也能用 +<== 这些符号——写出来的代码就像操作内置类型一样自然。竞赛中最常用的是 operator<,配合 sort 实现自定义排序。

本页目录
12.5.1 什么是运算符重载

C++ 内置的 intdouble 等类型可以直接用 +-< 这些符号运算。但如果你自己定义了一个 Point 类(表示二维坐标点),想把两个点相加,默认是不能直接写 p1 + p2 的——编译器不知道两个 Point 加在一起意味着什么。

运算符重载就是告诉编译器:当这个符号作用于我的类型时,应该做什么。

没有重载时
p1 + p2
❌ 编译错误
编译器不知道怎么加两个 Point

重载后
重载之后
p1 + p2
✅ 正常运行
返回新 Point(x1+x2, y1+y2)
12.5.2 基本语法

重载运算符用关键字 operator 后跟要重载的符号来定义,写在类内部:

C++ · 运算符重载的基本结构
1class MyClass {
2public:
3 // 返回值类型 operator符号 (参数) { ... }
4 MyClass operator+(const MyClass& other) {
5 // 定义 + 的行为,返回运算结果
6 }
7 bool operator<(const MyClass& other) {
8 // 定义 < 的行为,返回 true/false
9 }
10};
💡
参数为什么用 const &
const MyClass& other 而不是 MyClass other,是因为引用传参不需要复制对象(更快),const 则保证函数不会修改传入的参数。这是重载运算符的惯用写法。
12.5.3 重载加法运算符

以二维坐标点 Point 为例,重载 + 让两个点可以直接相加:

C++ · 重载 operator+
1struct Point {
2 int x, y;
3 Point(int x, int y) : x(x), y(y) {}
4
5 Point operator+(const Point& other) const {
6 return Point(x + other.x, y + other.y);
7 }
8
9 bool operator==(const Point& other) const {
10 return x == other.x && y == other.y;
11 }
12};
13
14int main() {
15 Point p1(1, 2), p2(3, 4);
16 Point p3 = p1 + p2; // → Point(4, 6),调用 operator+
17 cout << (p1 == p2); // → 0 (false),调用 operator==
18}
📌
注意第 5 行函数末尾的 const:这表示这个函数不会修改对象自身的数据。对于只做计算、不改状态的运算符(+==< 等),都应该加上这个 const
12.5.4 重载比较运算符与 sort

这是竞赛中运算符重载最常见、最实用的场景。std::sort 在排序时会调用 < 来比较元素大小。只要你的类重载了 operator<,就能直接用 sort 排序,无需额外写比较函数。

C++ · operator< 配合 sort 多关键字排序
1struct Student {
2 string name;
3 int score;
4 int age;
5
6 bool operator<(const Student& other) const {
7 if (score != other.score) // 第一关键字:分数降序
8 return score > other.score;
9 if (age != other.age) // 第二关键字:年龄升序
10 return age < other.age;
11 return name < other.name; // 第三关键字:姓名字典序
12 }
13};
14
15int main() {
16 vector<Student> v = {
17 {"Alice", 95, 16},
18 {"Bob", 82, 17},
19 {"Carol", 95, 15},
20 };
21 sort(v.begin(), v.end()); // 自动调用 operator<
22 // 排序结果:Carol(95,15) → Alice(95,16) → Bob(82,17)
23}
sort(v.begin(), v.end()) 遇到需要比较两个元素时 自动调用 operator<(a, b) 你定义的比较逻辑,返回 true/false 排序前 Alice 95 16 Bob 82 17 Carol 95 15 排序后 Carol 95 15 Alice 95 16 Bob 82 17 分数相同时比年龄,年龄也相同时比姓名——多关键字排序只需在 operator< 里依次判断
sort 内部每次比较两个元素时,都会调用你写的 operator<
你只需要定义"什么叫做 a 比 b 小",sort 就能帮你排好整个序列。
🏆
priority_queue 也一样:priority_queue 默认也用 operator< 来比较优先级。重载了 operator<,自定义类型就能直接放进优先队列,无需额外写仿函数。
12.5.5 重载流输出运算符

重载 << 之后,就可以直接用 cout << p 打印自定义类型,调试起来非常方便。

这个运算符比较特殊,必须写成类外的全局函数,因为左边是 ostream 而不是你的类:

C++ · 重载 operator<<
1struct Point {
2 int x, y;
3 Point(int x, int y) : x(x), y(y) {}
4};
5
6// 写在类外,第一个参数是 ostream&
7ostream& operator<<(ostream& os, const Point& p) {
8 os << "(" << p.x << ", " << p.y << ")";
9 return os; // 返回 os 以支持链式调用
10}
11
12int main() {
13 Point p(3, 4);
14 cout << p << endl; // 输出:(3, 4)
15 cout << p << " and " << p; // 链式调用也正常
16}
12.5.6 使用规则与注意事项
运算符常见用途写在类内 / 类外
+ - * / 向量、矩阵、复数等数学对象的运算 类内(推荐)
< > == != 配合 sort、priority_queue、set 的比较逻辑 类内(推荐)
<< >> cout / cin 输出输入自定义类型,调试常用 必须写在类外
[] 自定义容器的下标访问 类内
++ -- 迭代器等场景的自增自减 类内
⚠️
三条不能打破的规则:
① 只能重载已有的运算符,不能发明新符号(比如 ** 表示乘方)。
② 不能改变运算符的优先级结合性——* 永远比 + 先算。
③ 不能重载 ::.?:sizeof 这几个特殊运算符。
📖
本节小结
・用 operator符号 定义运算符的行为,让自定义类型像内置类型一样好用。
・竞赛中最常用的是 operator<,写好之后 sortpriority_queue 都能直接用。
operator<< 需要写在类外,返回 ostream& 以支持链式输出。
・不能改变优先级,不能创造新符号。