不能重载的运算符只有5个:::、.、.*、sizeof、?:;其余均可重载,但须遵守语义、操作数个数、优先级和结合性四条铁律,且至少一个操作数必须是用户定义类型。

不能重载的运算符只有 5 个:::、.、.*、sizeof、?:;其余所有运算符都可重载,但必须遵守语义、操作数个数、优先级和结合性这四条铁律。
哪些运算符根本不能重载
编译器直接禁止重载以下 5 个运算符,写 operator:: 或 operator. 会报错(如 error: ‘operator.’ must be a non-static member):
-
::(作用域解析)——它不作用于对象,没有调用上下文 -
.(成员访问)——语言层面绑定对象与成员,无法插入用户逻辑 -
.*(成员指针解引用)——语义太底层,且涉及对象布局细节 -
sizeof——编译期常量,结果由类型定义决定,不可干预 -
?:(三目条件)——短路求值 + 控制流语义,重载会破坏执行顺序保证
重载后必须保持原有语法结构
你改不了它的“长相”和“行为框架”,只能填充内部逻辑:
-
+必须是二元运算符:左侧一个操作数,右侧一个操作数,不能变成a + b + c以外的形式(链式调用是返回引用的结果,不是语法改变) -
++前置和后置必须靠参数区分:operator++()(无参) vsoperator++(int)(哑元int) -
=、[]、()、->只能作为成员函数重载——因为它们隐含this->绑定,非成员函数无法表达这种左值语义 - 重载
或 <code>>>必须用友元函数——否则左侧是std::ostream类型,不是你的类,没法当this
为什么不能给内置类型重载运算符
比如写 int operator+(int a, int b) { return a - b; } 是非法的,原因很实际:
- 编译器对
int + int的处理走的是硬编码路径,不进重载决议(overload resolution) - 允许这么做会破坏所有已有代码:别人写的
a + b突然变减法,谁都受不了 - 标准明确要求:至少一个操作数必须是用户定义类型(类 / 枚举 / 别名模板等),否则重载函数不参与匹配
默认参数和 const 修饰的陷阱
这两点容易在实现时忽略,但编译器会静默拒绝或导致行为异常:
- 重载函数不能带默认参数:比如
operator+(const A& rhs, int scale = 1)—— 这会让二元运算符看起来像一元,违反“操作数个数不变”规则,编译失败 - 成员重载函数该加
const就得加:bool operator。漏掉末尾 <code>const会导致不能对const A对象调用比较,STL 容器(如std::set)内部就会编译不过 - 赋值运算符
operator=必须返回A&(非常量引用),否则a = b = c链式赋值失效
真正麻烦的从来不是“怎么写出来”,而是“怎么让它在各种上下文中都不出错”:隐式转换、const 正确性、移动语义兼容、ADL 查找……这些细节一旦漏掉,问题往往出现在别人调用你类的时候,而不是你写重载函数的那一刻。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











