运算符重载入门
更新时间:2026-08-27。本文是
languages/cpp/主题入门层第 24 篇。运算符重载让+、<<、==这些符号能用在自定义类型上:v1 + v2、cout << p不再只是内建类型的特权。它有两种写法(成员函数 / 全局函数),全局写法往往要拉着友元出场。
本文要回答的问题
- 运算符重载是什么?凭什么让
+认识自定义类型? - 成员函数和全局函数两种写法怎么选?
- 为什么
operator<<必须用全局函数 + 友元?
一、运算符也是函数
1 + 2 在 C 里就是内建行为;C++ 允许你给类定义"这个类怎么参与 +"。写法是把运算符变成函数:
class Vector2 {
public:
double x_, y_;
Vector2(double x, double y) : x_(x), y_(y) {}
Vector2 operator+(const Vector2& other) const { // 成员函数形式
return Vector2(x_ + other.x_, y_ + other.y_);
}
bool operator==(const Vector2& other) const {
return x_ == other.x_ && y_ == other.y_;
}
};
Vector2 a(1, 2), b(3, 4);
Vector2 c = a + b; // 等价于 a.operator+(b)
if (a == b) { /* ... */ }a + b 被编译器翻译成 a.operator+(b)——成员函数形式下,左操作数是 this,右操作数是参数。operator+ 就是函数名,+ 只是个记号。
二、两种写法怎么选
| 形式 | 写法 | 左操作数 | 适用场景 |
|---|---|---|---|
| 成员函数 | Vector2 operator+(...) | 必须是本类对象 | 左边总是自己的类型 |
| 全局函数 | Vector2 operator+(const Vector2&, const Vector2&) | 可以是任意类型 | 两边都可能不是本类 |
成员函数简单直接,但有个硬限制:左操作数必须是本类的对象。比如 2.0 * v(double 在左边)写成成员函数就不行——2.0 不是 Vector2 对象。这时用全局函数:
Vector2 operator*(double k, const Vector2& v) { // 全局
return Vector2(k * v.x_, k * v.y_);
}
Vector2 operator*(const Vector2& v, double k) { // 再写一个对称的
return Vector2(v.x_ * k, v.y_ * k);
}
Vector2 r = 2.0 * v; // 调全局版本
Vector2 s = v * 2.0; // 调对称版本经验法则:左操作数是本类 → 成员函数;左操作数可能是别的类型 → 全局函数。加减乘除(对称运算符)很多项目统一用全局函数,两边平等对待。
三、operator<<:为什么必须全局 + 友元
std::cout << p;<< 的左边是 std::cout(ostream 对象),不是你的类。所以只能写全局函数。但全局函数要读 p 的私有成员 x_、y_——上一篇文章的友元正好派上用场:
class Point {
int x_, y_;
public:
Point(int x, int y) : x_(x), y_(y) {}
friend std::ostream& operator<<(std::ostream& os, const Point& p) {
os << "(" << p.x_ << ", " << p.y_ << ")";
return os;
}
};
Point pt(1, 2);
std::cout << pt; // 输出 (1, 2)两个细节:
- 返回
std::ostream&(还是那个 cout),才能支持cout << p << " done"连环输出——和上一篇的*this链式同理; - 上面把函数体直接写在
friend声明里(类内友元定义),简洁常见。
四、哪些运算符能重载
| 能重载 | 不能重载 |
|---|---|
+ - * / %、== != < >、<< >>、[]、()、++ --、`&& |
规则:只能重载已有的运算符,不能发明新符号;::、.、?: 这类语义太内核的禁止重载。运算符重载没法改变优先级和结合性——a + b * c 永远先乘后加。
五、和 C 对比
| 对比项 | C | C++ |
|---|---|---|
| 结构体运算 | 手写 add(v1, v2) 函数 | v1 + v2 运算符重载 |
| 打印结构体 | print(&p) 手写格式 | cout << p 重载 << |
| 比较结构体 | memcmp 或逐字段 | 重载 == |
| 滥用风险 | 无 | 语义混乱(+ 做减法) |
C 里对结构体做加法就是 add(&a, &b)——没错,但读代码时"这是在加向量"要再想一步。C++ 重载 + 后 a + b 直读。代价是纪律:重载要符合直觉,+ 就该是加法语义,operator+ 内部偷偷做减法属于给后人埋雷。
六、与本站主线衔接
- 友元与运算符重载的配合,回看 友元;
operator[](下标)、operator()(仿函数)等进阶重载见高手层;- 下一篇:const 成员函数——给"只读操作"上锁。
一句话总结
运算符重载把 +、<<、== 变成成员函数或全局函数,让自定义类型享受内建语法;左操作数是本类用成员函数,可能是别的类型用全局函数;operator<< 必须全局 + 友元(读私有成员 + 左边是 cout);只能重载已有运算符、不能改优先级,重载语义必须符合直觉。
上一篇:友元 下一篇:const 成员函数