C++ 运算符重载是面向对象编程的核心知识点,也是面试、考试的高频考点,更是新手最容易混淆的模块。很多同学学到这里都会被哪些运算符不能重载、哪些只能写成员函数、重载规则、返回值 / 引用区别绕晕。
一、不能重载的 5 个运算符
C++ 语法硬性规定,以下运算符不允许重载:
| 运算符 | 名称 | 禁止原因 |
|---|---|---|
. | 成员访问运算符 | 语言基础语法,不可修改 |
.* | 成员指针访问运算符 | 用于访问类成员指针,语法固定 |
:: | 作用域限定符 | 用于区分命名空间 / 类作用域,语法固定 |
?: | 三目条件运算符 | 语法结构特殊,无法重载 |
sizeof | 求类型大小运算符 | 编译期计算,非运行期运算符 |
二、只能作为类成员函数重载的 4 个运算符
这 4 个运算符不允许写成全局函数,必须定义在类内部:
| 运算符 | 名称 | 必须成员重载原因 |
|---|---|---|
= | 赋值运算符 | 编译器会默认生成,必须成员函数 |
[] | 下标运算符 | 依赖对象本身,必须绑定实例 |
() | 函数调用运算符 | 让对象可像函数一样调用,必须成员 |
-> | 指针成员访问运算符 | 智能指针核心运算符,必须成员 |
三、运算符重载的 6 大核心规则(必背)
这是编译器强制遵守的语法规则,违反直接报错:
1. 操作数必须包含自定义类型
重载的运算符,至少有一个操作数是 类 / 结构体 / 枚举类型。
错误:不能重载两个内置类型的运算符
// 报错!两个int都是内置类型,无法修改原有规则
int operator+(int a, int b) { return a+b; }
✅ 正确:必须包含自定义类类型
class Complex{/*...*/};
Complex operator+(Complex c1, Complex c2); // 合法
2. 不能改变运算符优先级
例如 * 优先级高于 +,重载后依然不变,无法修改。
3. 不能改变运算符结合性
例如 a+b+c 依然从左到右计算,无法修改。
4. 不能改变操作数个数
双目运算符(+、-、*)重载后还是双目;单目运算符(++、--、!)重载后还是单目。
5. 不能自创运算符
只能重载 C++ 原生运算符,不能自己造 $、#、@ 等新符号。
6. 语义必须符合直觉
重载运算符要遵循原有含义:+ 表示相加、== 表示判等、[] 表示下标访问,不要乱写语义!
四、关键概念:成员函数 VS 全局函数 参数区别
这是最容易错的点,核心原因:成员函数自带隐藏的 this 指针!
1. 成员函数重载(类内)
- 双目运算符:只需要 1 个显式参数(左操作数是 this)
- 单目运算符:0 个显式参数
// 成员函数:a + b → a.operator+(b)
Complex operator+(const Complex& other) const;
2. 全局函数重载(类外)
- 双目运算符:需要 2 个参数
- 单目运算符:需要 1 个参数
// 全局函数:a + b → operator+(a,b)
Complex operator+(const Complex& c1, const Complex& c2);
五、运算符返回引用 VS 返回值
C++ 没有强制规定,但工程开发有统一约定:
1. 必须 / 通常返回 引用 的运算符
适用场景:返回对象本身、支持连续操作、支持赋值修改
| 运算符 | 示例 | 返回值类型 |
|---|---|---|
赋值 = | a = b = c | 类& |
下标 [] 非 const | arr[0] = 10 | 元素类型& |
前置自增 / 自减 ++a --a | ++a | 类& |
流运算符 << >> | cout<<a<<b | ostream&/istream& |
核心原因:返回引用才能实现连续调用、修改原对象!
2. 必须 / 通常返回 值 的运算符
适用场景:产生新对象、不修改原操作数、返回临时结果
| 运算符 | 示例 | 返回值类型 | ||
|---|---|---|---|---|
算术运算符 + - * / % | a + b | 新对象 | ||
后置自增 / 自减 a++ a-- | a++ | 旧值副本 | ||
比较运算符 == != < > | a == b | bool | ||
| 逻辑运算符 `! && | ` | !a | bool |
核心原因:运算结果是临时新值,和原对象无关,必须返回值!
六、完整实战代码
#include <iostream>
using namespace std;
// 复数类:演示运算符重载
class Complex {
public:
Complex(double real = 0, double imag = 0) : _real(real), _imag(imag) {}
// 1. 赋值运算符 = :返回引用(成员函数)
Complex& operator=(const Complex& other) {
if (this != &other) {
_real = other._real;
_imag = other._imag;
}
return *this;
}
// 2. 加法运算符 + :返回值(成员函数)
Complex operator+(const Complex& other) const {
return Complex(_real + other._real, _imag + other._imag);
}
// 3. 前置++ :返回引用
Complex& operator++() {
_real++;
_imag++;
return *this;
}
// 4. 后置++ :返回值
Complex operator++(int) {
Complex temp = *this;
_real++;
_imag++;
return temp;
}
// 5. 下标运算符 [] :返回引用
double& operator[](int index) {
if (index == 0) return _real;
else return _imag;
}
// 6. 比较运算符 == :返回bool
bool operator==(const Complex& other) const {
return _real == other._real && _imag == other._imag;
}
// 友元声明:流运算符
friend ostream& operator<<(ostream& out, const Complex& c);
friend istream& operator>>(istream& in, Complex& c);
private:
double _real;
double _imag;
};
// 流输出 << :返回引用(全局函数)
ostream& operator<<(ostream& out, const Complex& c) {
out << c._real << " + " << c._imag << "i";
return out;
}
// 流输入 >> :返回引用(全局函数)
istream& operator>>(istream& in, Complex& c) {
in >> c._real >> c._imag;
return in;
}
// 测试
int main() {
Complex c1(1, 2), c2(3, 4);
Complex c3 = c1 + c2;
cout << "c1 + c2 = " << c3 << endl;
++c1;
cout << "前置++ c1: " << c1 << endl;
c2++;
cout << "后置++ c2: " << c2 << endl;
cout << "c1[0] = " << c1[0] << endl;
c1[0] = 10;
cout << "修改后c1: " << c1 << endl;
return 0;
}
七、速记表
1. 不能重载
. .* :: ?: sizeof
2. 只能成员重载
= [] () ->
3. 重载核心规则
至少一个自定义类型 + 不改变优先级 / 结合性 / 参数个数
4. 返回引用
= [] 前置++/-- << >>
5. 返回值
+ - * / % 后置++/-- == != < > !
总结
运算符重载的核心就两点:
- 遵守语法规则:记住不能重载、只能成员重载的运算符;
- 遵循语义规范:修改自身 / 连续操作返回引用,产生新结果返回值。

8794

被折叠的 条评论
为什么被折叠?



