加法重载不必强制为成员或友元函数,但友元更灵活,支持对称运算和隐式转换;返回值应为 const 值类型(如 const vec2),避免悬垂引用和非法赋值。

加法重载必须定义为成员函数还是友元函数?
不是必须,但选择影响访问权限和参数顺序。operator+ 可以是类的 public 成员函数,也可以是全局友元函数。成员版本自动获得 this 指针,左操作数固定为当前对象;友元版本更灵活,能对称处理两个自定义类型(比如 a + b 和 b + a 都走同一份逻辑),也方便支持隐式转换(如 MyInt + 5)。如果希望支持 int + MyInt 这种左操作数是非类类型的场景,只能靠友元或非成员函数,因为成员函数的左操作数总是类类型。
为什么返回值要声明为 const 值类型而不是引用?
因为加法结果是临时对象,不是已有对象的别名。operator+ 的语义是“产生新值”,返回局部对象或右值时若用 const T& 就会绑定到即将销毁的临时量,导致悬垂引用。正确做法是返回 T(值返回)。加上 const(即 const T)可防止写出 (a + b) = c 这类无意义赋值(虽然 C++17 后对纯右值赋值本身已报错,但保留 const 是惯用写法,且能提前拦截部分误用)。
常见错误:把 operator+ 声明成 void 或返回引用
典型错误包括:
- 写成
void operator+(const T& rhs)—— 忘了返回新对象,调用时无法链式使用(如a + b + c) - 写成
T& operator+(const T& rhs)—— 返回局部变量引用,运行时行为未定义 - 在成员函数中直接修改
this—— 加法不该改变原对象,应保持 const-correctness;正确做法是用const成员函数 + 创建新对象 - 没把参数设为
const T&—— 导致无法传入临时量或字面量,比如a + MyType(3)会编译失败
一个安全、可读的实现模板(以 Vec2 为例)
假设 Vec2 有 x, y 成员:
class Vec2 {
public:
float x = 0, y = 0;
Vec2(float x = 0, float y = 0) : x(x), y(y) {}
// 成员版本(支持 Vec2 + Vec2)
Vec2 operator+(const Vec2& rhs) const {
return Vec2(x + rhs.x, y + rhs.y);
}
// 友元版本(更推荐,支持 Vec2 + Vec2 和 int/float + Vec2)
friend Vec2 operator+(const Vec2& lhs, const Vec2& rhs) {
return Vec2(lhs.x + rhs.x, lhs.y + rhs.y);
}
};
注意:如果同时提供成员和友元,容易引发重载歧义;一般二选一。多数现代代码库倾向用友元,尤其当需要支持混合类型运算时。另外,C++20 起可用 = default 让编译器生成,但前提是类满足 trivially copyable 等条件,且不涉及资源管理——这种“零开销”方式只适用于非常简单的聚合类型。
最容易被忽略的是:一旦重载了 operator+,别忘了配套检查是否需要 operator+=(它应该修改左操作数并返回 *this&),否则 a += b 会退化为 a = a + b,多一次拷贝。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











