重载运算符必须是类的成员函数或友元函数:非静态成员函数可直接访问私有成员,友元全局函数需显式声明friend才能访问;普通自由函数因无法访问私有成员而不可行。

重载运算符必须是类的成员函数或友元函数
不是所有函数都能随便重载运算符——C++ 要求 operator+、operator== 这类运算符重载,要么是类的非静态成员函数,要么是声明为 friend 的全局函数。普通自由函数(非友元)无法访问私有成员,基本没法实现有意义的重载。
常见错误是写成:
MyClass operator+(MyClass a, MyClass b) { ... } // ❌ 缺少 friend 声明,且无法访问私有成员
结果编译报错:error: 'int MyClass::val' is private。- 二元运算符如
+、==、,推荐用友元函数实现,语义对称(<code>a + b和b + a可一致处理) - 一元运算符如
++、-、!,优先用成员函数(隐式this参数更自然) - 赋值运算符
operator=必须是成员函数,且不能是friend
前置++和后置++的签名和返回值完全不同
很多人以为 operator++() 就够了,其实 C++ 靠参数列表区分前置与后置:后置版本**必须带一个 int 形参**(仅作标记,不使用),且返回旧值(通常为值拷贝);前置版本返回引用(支持链式调用)。
错误写法示例:
MyClass& operator++() { /* 前置 */ return *this; }
MyClass operator++() { /* 后置?❌ 编译失败:重定义 */ return old; }
正确写法:
MyClass& operator++() { /* 前置 */ ++val; return *this; }
MyClass operator++(int) { /* 后置 */ MyClass tmp = *this; ++val; return tmp; }
- 后置版本返回
MyClass(不是MyClass&),否则返回局部对象引用是未定义行为 - 前置版本返回
MyClass&,才能支持++(++a)这类连续调用 - 如果类含指针或动态资源,后置版本的拷贝开销可能显著,需权衡
赋值运算符重载要处理自赋值和深拷贝
默认生成的 operator= 是浅拷贝,遇到指针成员极易引发 double-free 或悬垂指针。手动重载时,第一件事就是检查自赋值:if (this == &other) return *this;。
典型陷阱代码:
MyClass& operator=(const MyClass& other) {
delete[] data;
data = new int[other.size];
memcpy(data, other.data, other.size * sizeof(int));
size = other.size;
return *this;
}
这段代码在 a = a; 时会先 delete[] data,再用已释放的 other.data 拷贝——崩溃。
- 务必在开头加自赋值检查
- 若涉及堆内存,优先用“拷贝-交换”惯用法(copy-and-swap),天然避免自赋值问题且异常安全
- 不要返回
void;必须返回MyClass&,以支持a = b = c链式赋值
哪些运算符不能重载
不是所有符号都能重载。C++ 明确禁止重载以下 5 个:?:(三目)、.(成员访问)、.*(成员指针访问)、::(作用域解析)、sizeof。试图重载会直接编译失败,报错类似:error: 'operator?:' cannot be overloaded。
另外要注意:
- 不能改变运算符的优先级、结合性或操作数个数
- 不能创建新运算符(比如
**或===) -
new和delete可重载,但必须严格匹配签名(如void* operator new(size_t)),否则链接失败
重载的本质是让自定义类型“看起来像内置类型”,但越贴近,越要小心语义一致性——比如 operator== 应满足自反性、对称性、传递性,否则用在 std::map 或 std::unordered_map 里会出乎意料地崩。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











