可重载 vs 不可重载
可重载:
算术: + - * / % += -= *= /= %=
比较: < > <= >= == !=
位: & | ^ ~ << >> &= |= ^= <<= >>=
逻辑: ! && ||
赋值: =
下标: []
调用: ()
解引用: * ->
自增: ++ --
new / delete
不可重载:
:: . .* ?: sizeof typeid
基本原则
// ① 成员 vs 非成员
class Vec2 {
double x, y;
public:
// 成员函数:第一个操作数必须是本类
Vec2 operator+(const Vec2 &other) const {
return {x + other.x, y + other.y};
}
// 好处:可访问私有成员
// 非成员(推荐对称运算符):
friend Vec2 operator*(double s, const Vec2 &v) {
return {s * v.x, s * v.y};
}
// 好处:3.0 * v 可以(左操作数隐式转换)
};
// ② 返回 const 引用的规则
// = += -= → 返回 *this 的引用(支持链式 a=b=c)
// + - * / → 返回新对象(值语义)
// < > == → 返回 bool
// ③ 不要重载逻辑运算符的短路行为
// operator&& — 两个操作数都会求值!已失去短路语义
// 基本不重载 &&
算术运算符
class Complex {
double re, im;
public:
// 复合赋值(成员,返回引用)
Complex &operator+=(const Complex &rhs) {
re += rhs.re; im += rhs.im;
return *this;
}
// 二元 +(非成员,用 += 实现)
friend Complex operator+(Complex lhs, const Complex &rhs) {
lhs += rhs; // 拷贝 lhs,然后 +=
return lhs; // 利用 RVO
}
// 技巧:operator+ 不访问私有成员 → 只需 operator+=
};
比较运算符(C++20 简化)
// C++17 之前 — 写 4-6 个
class Person {
string name; int age;
public:
bool operator==(const Person &o) const { return name == o.name && age == o.age; }
bool operator!=(const Person &o) const { return !(*this == o); }
bool operator< (const Person &o) const { return tie(name, age) < tie(o.name, o.age); }
};
// C++20 — 只需 <=>
class Person20 {
string name; int age;
public:
auto operator<=>(const Person20 &) const = default; // 一行生成全部 6 个!
};
下标与函数调用
// 下标 operator[]
class Array {
int *data; size_t n;
public:
int &operator[](size_t i) { return data[i]; } // 可写
int operator[](size_t i) const { return data[i]; } // 只读版
};
// 函数调用 operator() → 仿函数
class Multiplier {
int factor;
public:
Multiplier(int f) : factor(f) {}
int operator()(int x) const { return x * factor; }
};
Multiplier times3(3);
int nine = times3(3); // 像函数一样调用
// 结合 std::function / 算法
vector<int> v = {1, 2, 3};
transform(v.begin(), v.end(), v.begin(), Multiplier(10));
类型转换运算符
class Wrapper {
int value;
public:
// 隐式转换(方便但危险)
operator int() const { return value; } // Wrapper → int
// C++11 explicit — 必须显式转换
explicit operator bool() const { return value != 0; }
};
Wrapper w{42};
int i = w; // ✅ 隐式
// bool b = w; // ❌ explicit
bool b = bool(w); // ✅ 显式
if (w) { /* ... */ } // ✅ 条件上下文允许 explicit bool
增量运算符
class Iterator {
int pos;
public:
Iterator &operator++() { ++pos; return *this; } // 前置 ++it
Iterator operator++(int) { auto tmp = *this; ++pos; return tmp; } // 后置 it++
// ↑ 哑元 int 区分前后置
};
输出运算符
class Point {
double x, y;
friend ostream &operator<<(ostream &os, const Point &p) {
return os << "(" << p.x << ", " << p.y << ")";
}
};
// 必须是非成员:第一个参数是 ostream,不能是本类
经验法则
1. = [] () -> → 成员函数(别无选择)
2. += -= *= /= → 成员函数
3. + - * / → 非成员(用 += 实现)
4. == < > → 非成员(对称性)
5. << >> → 非成员(第一个参数是 stream)
6. 不要重载 && || ,(破坏短路/求值顺序)