C++ 的运算符重载(Operator Overloading)是其强大扩展性的体现,它允许开发者赋予内置运算符(如+,-,*,<<等)处理自定义类对象的能力。
1. 基本规则与限制
在开始编写代码前,必须牢记以下“死理”:
不能创建新运算符:你只能重载 C++ 语法中已有的运算符(例如不能造一个 表示幂运算)。
不改变优先级和结合性:
*的优先级永远高于+。至少有一个参数是类类型:不能重载处理两个
int的运算符。不可重载的运算符:
.(成员访问).*(成员指针访问)::(域解析)?:(条件运算符)sizeof,typeid,alignof
2. 重载方式:成员函数 vs. 非成员函数
A. 成员函数重载
运算符作为类的成员。第一个操作数必须是该类的对象(由this指针隐式传递)。
C++
Complex operator+(const Complex& other) const { return Complex(this->real + other.real, this->imag + other.imag); }B. 非成员函数(通常是友元)重载
如果左侧操作数不是该类的对象(例如int + Complex或cout << Complex),则必须使用非成员函数。
C++
friend Complex operator+(double left, const Complex& right);3. 分类知识点详解
3.1 算术运算符 (+,-,*,/)
通常返回一个新对象(传值返回)。建议先实现赋值运算符(如+=),再用+=实现+以减少代码冗余。
3.2 自增自减 (++,--)
分为前置和后置,通过一个占位参数int来区分:
前置:
Complex& operator++()(返回引用,效率高)后置:
Complex operator++(int)(返回原副本,效率低)
3.3 关系运算符 (==,!=,<,>)
必须返回bool类型。在 C++20 中,引入了“三路比较运算符”<=>(太空船运算符),只需定义它,编译器就能自动生成所有关系运算。
3.4 赋值运算符 (=)
必须是成员函数。
默认赋值:编译器会生成浅拷贝赋值,如果类中有指针,必须手动重载以实现深拷贝。
准则:检查自赋值(
if (this == &other)),返回*this的引用。
3.5 流运算符 (<<,>>)
必须是非成员函数。因为第一个参数是
std::ostream&或std::istream&。
C++
std::ostream& operator<<(std::ostream& os, const Complex& c) { os << c.real << " + " << c.imag << "i"; return os; // 支持链式调用 }3.6 函数调用运算符 (())
重载后,类的对象可以像函数一样被调用,这种对象称为仿函数(Functor)。
C++
struct Linear { double operator()(double x) { return a * x + b; } double a, b; };4. 特殊运算符
下标运算符
[]:通常提供const和非const两个版本。解引用运算符
*和->:常用于智能指针,必须返回指针或支持解引用的对象。类型转换运算符:例如
operator bool(),允许对象直接用于条件判断。建议加上explicit防止意外隐式转换。
5. 最佳实践建议 (Checklist)
| 场景 | 推荐做法 |
| 一致性 | 含义应与内置类型保持一致(别让+做减法)。 |
| 返回类型 | 赋值运算(=,+=)返回引用;算术运算(+,-)返回新值。 |
| 对称性 | 如果a + b能行,那么b + a也应该能行(通常用非成员函数实现)。 |
| 效率 | 参数尽可能使用const T&以避免不必要的拷贝。 |