目录
[二、铺垫 --- 类和构造函数](#二、铺垫 — 类和构造函数)
[三、运算符重载长啥样?operator 是硬条件](#三、运算符重载长啥样?operator 是硬条件)
[3.1 为啥一定要 operator+ 这种写法](#3.1 为啥一定要 operator+ 这种写法)
[3.2 普通函数写法:](#3.2 普通函数写法:)
[四、a + b 是怎么关联到 this 和 other 的?](#四、a + b 是怎么关联到 this 和 other 的?)
[4.1 调用写法:](#4.1 调用写法:)
[4.2 成员函数形式的运算符重载](#4.2 成员函数形式的运算符重载)
[4.3 表格](#4.3 表格)
[五、Vec2 operator+(const Vec2& other) const 逐词拆解](#五、Vec2 operator+(const Vec2& other) const 逐词拆解)
[5.1 函数"长相":](#5.1 函数“长相”:)
[5.2 它到底是什么](#5.2 它到底是什么)
[1) 成员函数形式的运算符重载](#1) 成员函数形式的运算符重载)
[5.3 参数:const Vec2& other 含义](#5.3 参数:const Vec2& other 含义)
[5.4 函数后面的 const 是什么](#5.4 函数后面的 const 是什么)
[5.5 返回值:Vec2](#5.5 返回值:Vec2)
[7.1 标准过程](#7.1 标准过程)
[7.2 链式加法](#7.2 链式加法)
[8.1 运算符重载本质上就是"函数重载语法糖"](#8.1 运算符重载本质上就是“函数重载语法糖”)
[8.2 成员版本 vs 非成员版本(全局函数)](#8.2 成员版本 vs 非成员版本(全局函数))
前言
在之前的学习中,已经详细的讲解了C++重载(函数重载 + 运算符重载)以及前置++和后置++的相关内容,链接如下:
一篇搞懂 C++ 重载:函数重载 + 运算符重载,从入门到会用(含 ++、<<、== 实战)-CSDN博客
https://blog.csdn.net/m0_58954356/article/details/155323257?sharetype=blogdetail&sharerId=155323257&sharerefer=PC&sharesource=m0_58954356&spm=1011.2480.3001.8118
【C++基础】Day 6:前置++ VS 后置++(语法底层 + STL规范 + 面试高频)-CSDN博客
https://blog.csdn.net/m0_58954356/article/details/155424877?spm=1001.2014.3001.5501但是后台还是有很多小伙伴私信,里面的示例代码看不懂,摸不清深层的重载概念,因此基于前一章做出一定延伸,详细讲解一下里面的示例代码,帮助大家更好的了解运算符重载的概念以及如何正确使用!
一、代码示例:
cpp
class Vec2 {
public:
double x, y;
Vec2(double x = 0, double y = 0) : x(x), y(y) {}
// 重载+运算符:成员函数版本
Vec2 operator+(const Vec2& other) const {
// 自定义"加法规则":x加x,y加y
return Vec2(x + other.x, y + other.y);
}
};
-
定义了一个 二维向量 类型:
Vec2,有两个成员:x和y。 -
为这个类型 重载了
+运算符,让你可以写:cppVec2 a(1.0, 2.0); Vec2 b(3.0, 4.0); Vec2 c = a + b; // 调用你重载的 Vec2::operator+
而不是自己写函数 add(a, b)。
这一小段 operator+,基本把 C++ 里成员运算符重载的关键点全包含了:
operator 关键字、this 和参数的关系、const Vec2& 的含义、函数后面的 const、以及调用时的翻译过程。
二、铺垫 --- 类和构造函数
cpp
class Vec2 {
public:
double x, y; // 成员变量,表示向量的两个分量
Vec2(double x = 0, double y = 0) // 构造函数,有默认参数
: x(x), y(y) {}
};
-
double x, y;一个二维向量,两个坐标
(x, y)。 -
构造函数
Vec2(double x = 0, double y = 0):-
Vec2 v;→(0, 0) -
Vec2 v(1.0);→(1.0, 0) -
Vec2 v(1.0, 2.0);→(1.0, 2.0)
-
注意:这里的
Vec2是构造函数名字 ,跟后面**Vec2 operator+里的Vec2(返回值类型)**不是一个概念,别混在一起。
这些只是为了能方便构造对象,真正的主角是下面的 operator+。
三、运算符重载长啥样?operator 是硬条件
函数声明:
cpp
Vec2 operator+(const Vec2& other) const;
拆开看:
返回类型:
Vec2函数名:
operator+参数:
const Vec2& other函数后缀:
const
3.1 为啥一定要 operator+ 这种写法
因为 C++ 规定:所有运算符重载函数的名字,都必须以 operator 开头,后面跟运算符符号 :
operator+
operator-
operator*
operator/
operator==
operator<<
operator[]
operator()...

3.2 普通函数写法:
1)示例:
cpp
class Vec2 {
public:
double x, y;
Vec2(double x = 0, double y = 0) : x(x), y(y) {} //构造函数
// 普通函数,不是运算符重载
Vec2 add(const Vec2& other) {
return Vec2(x + other.x, y + other.y);
}
};
2)解析:
那它只是个普通函数,编译器不会把 a + b 翻译成 a.add(b),你只能手动调用:
cpp
Vec2 a(1, 2);
Vec2 b(3, 4);
Vec2 c = a.add(b); // ✔️ add 是普通函数,可以调用
Vec2 c2 = a + b; // ❌ 没有 operator+ 会编译失败
3)解释:
-
a.add(b)的意思是
"调用对象 a 的成员函数 add,并把 b 作为参数传进去" -
就像你调用任何成员函数一样:
cppobject.function(parameter)
它跟运算符一点关系也没有。
一句话:想用 a + b 这种写法,就必须写 operator+,不叫这个名字就不算运算符重载。
四、a + b 是怎么关联到 this 和 other 的?
4.1 调用写法:
cpp
Vec2 a(1.0, 2.0);
Vec2 b(3.0, 4.0);
Vec2 c = a + b;
4.2 成员函数形式的运算符重载
在 成员函数形式的运算符重载 下,编译器会把它翻译成:
cpp
Vec2 c = a.operator + (b);
// ^ ^
// this other
于是:
a 是调用者 → 对应成员函数里的隐式参数 this
b 是传进去的参数 → 对应形参 other
4.3 表格
| 代码位置 | 它是谁 | 在函数内部怎么访问 |
|---|---|---|
a |
this |
this->x, this->y 或简写为 x, y |
b |
other |
other.x, other.y |
所以,在函数体里:
cpp
return Vec2(x + other.x, y + other.y);
实际上就是:
cpp
return Vec2(this->x + other.x,
this->y + other.y);
五、Vec2 operator+(const Vec2& other) const 逐词拆解
cpp
Vec2 operator+(const Vec2& other) const {
return Vec2(x + other.x, y + other.y);
}
5.1 函数"长相":
函数名:
operator+参数:
const Vec2& other返回值类型:
Vec2末尾有
const
5.2 它到底是什么
1) 成员函数形式的运算符重载
这是一个 成员函数形式的运算符重载。
等价于定义了一个成员函数:
cpp
Vec2 Vec2::operator + (const Vec2& other) const;
2)编译器看到
编译器看到你写:
cpp
Vec2 c = a + b;
3)编译器翻译
会翻译成:
cpp
// 当前对象.operator+(传进来的参数对象)
Vec2 c = a.operator + (b);
4)解析
a 是调用者 → 对应成员函数里的隐式参数 this
b 是传进去的 other
5)表格
| 代码位置 | 它是谁 | 解释 |
|---|---|---|
| a | this |
隐式的对象指针,代表"当前对象" |
| b | other |
明确写在参数列表里的那个引用参数 |
5.3 参数:const Vec2& other 含义
1)含义
这里的参数写法非常典型,含义分三层:
-
&:引用-
不拷贝对象,直接绑定到传进来的那个对象
b -
效率高,尤其是对象比较大时
-
-
const:不能通过这个引用去修改对象-
"const 确定了 other 引用的值不能改变吗"
-
在函数体里,下面这样做是非法的:
cppother.x = 10; // ❌ 编译不过
-
-
合起来
const Vec2&:"只读引用参数 ":
可以高效访问 b,但不能在这个函数里修改 b。
5.4 函数后面的 const 是什么
cpp
Vec2 operator+(const Vec2& other) const
↑
这个**const** 修饰的是 成员函数本身,表示:
这个函数不会修改当前对象(也就是
this指向的那个对象)。
在语义上,可以理解为在函数体里 this 的类型是:
cpp
const Vec2* const this;
// ^^^^^^^ 不能通过 this 修改成员
// ^^^^^^^ this 指针本身也不能改指向
所以在函数体里,下面这样也是不允许的:
cpp
x = 10; // ❌ 编译不过
this->y = 5; // ❌ 编译不过
这也符合"加法"语义:
c = a + b; → 应该只返回一个新结果 c,而不去修改 a 或 b 自身。
小结:
参数前的 const → 限制你不能改 other(b)
函数后的 const → 限制你不能改 this(a)
5.5 返回值:Vec2
cpp
Vec2 operator + (const Vec2& other) const {
return Vec2(x + other.x, y + other.y);
}
-
产生了一个 新的 Vec2 对象,代表"相加后的结果"。
-
局部临时对象,返回时会执行返回值优化 / 移动,不用太担心性能。
加法通常是"产生一个新对象",所以返回值用 值返回 很自然。
六、函数体逻辑:自定义"加法规则"
核心:
cpp
return Vec2(x + other.x, y + other.y);
也就是:
cpp
return Vec2(this->x + other.x, this->y + other.y);
几何意义:
当前对象:
(x, y)(也就是a)参数对象:
(other.x, other.y)(也就是b)结果对象:
(x + other.x, y + other.y)(也就是c)
你完全可以写成其他规则(虽然不建议乱写):
cpp
return Vec2(x + other.x, y - other.y); // y 分量用减法
这就体现了运算符重载最关键的一点:
运算符重载只是一种"外壳语法",具体行为完全由你在函数体里定义。
七、真实调用过程再走一遍(含链式加法)
7.1 标准过程
1)代码:
cpp
Vec2 a(1.0, 2.0);
Vec2 b(3.0, 4.0);
Vec2 c = a + b;
2)编译器理解为:
cpp
Vec2 c = a.operator+(b);
3)调用过程:
-
生成对象
a(1, 2),b(3, 4); -
调
a.operator+(b):-
this->x = 1,this->y = 2 -
other.x = 3,other.y = 4
-
-
计算并返回
Vec2(4, 6)赋给c。
7.2 链式加法
1)代码:
cpp
Vec2 d = a + b + c;
2)翻译过程:
cpp
Vec2 tmp = a.operator+(b); // tmp 是 (4, 6)
Vec2 d = tmp.operator+(c); // 再用 tmp + c
3)解释:
原因很简单:
每次 + 都返回一个新的 Vec2,所以结果继续能当左操作数用。
八、和普通函数重载的关系
8.1 运算符重载本质上就是"函数重载语法糖"
你完全可以不用 operator+,写成普通函数:
cpp
Vec2 add(const Vec2& a, const Vec2& b) {
return Vec2(a.x + b.x, a.y + b.y);
}
Vec2 c = add(a, b); // 功能一样,只是写法不那么直观
operator+ 只是让你可以用:
cpp
a + b;
而不是:
cpp
add(a, b);
可读性更好,更贴近数学。
8.2 成员版本 vs 非成员版本(全局函数)
1)成员版本:
现在你写的是 成员版本:
cpp
Vec2 Vec2::operator+(const Vec2& other) const;
2)非成员版本
如果写成非成员函数版本,会是这样:
cpp
Vec2 operator+(const Vec2& lhs, const Vec2& rhs) {
return Vec2(lhs.x + rhs.x, lhs.y + rhs.y);
}
3)调用
cpp
Vec2 c = a + b; // 调用 ::operator+(a, b)
4)差别
两种版本有一些差别,比如:
成员版:左边一定是 Vec2 或能隐式转换成 Vec2
非成员版:两边都作为参数传入,有时候对"对称运算符"(如 ==、+)会更灵活
九、运算符重载的一些面试问题
-
不能发明新运算符
只能重载已有的**:
+ - * / [] () == << >>** 等。 -
重载不会改变优先级和结合性
a + b * c还是先乘后加,重载不影响运算符优先级。 -
最好保证语义直观
+就应是"加法",不要拿它实现奇怪行为(容易坑队友)。 -
const正确性很重要-
参数用 const T&:不改参数
-
成员函数后加 const:不改当前对象
这两个在写类库/八股题时是加分项
-
十、总结
a + b在成员运算符重载形式下,会被翻译成a.operator+(b)
a→this(隐式参数)
b→other(显式参数)
const Vec2& other表示:按引用接收参数,不能在函数里改它。函数末尾的
const表示:这个函数不会修改当前对象(this)。写成
Vec2 operator+(...)是因为:
前面的
Vec2是返回值类型
operator+是一个特殊命名的函数名,用于告诉编译器"这是 + 运算符的重载"。运算符重载本质上是普通函数 + 特定命名 + 语法糖 ,逻辑完全是你在函数体里定义的。