C++ 成员函数运算符重载深度解析

目录

前言

一、代码示例:

[二、铺垫 --- 类和构造函数](#二、铺垫 — 类和构造函数)

[三、运算符重载长啥样?operator 是硬条件](#三、运算符重载长啥样?operator 是硬条件)

[3.1 为啥一定要 operator+ 这种写法](#3.1 为啥一定要 operator+ 这种写法)

[3.2 普通函数写法:](#3.2 普通函数写法:)

1)示例:

2)解析:

3)解释:

[四、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) 成员函数形式的运算符重载)

2)编译器看到

3)编译器翻译

4)解析

5)表格

[5.3 参数:const Vec2& other 含义](#5.3 参数:const Vec2& other 含义)

1)含义

[5.4 函数后面的 const 是什么](#5.4 函数后面的 const 是什么)

[5.5 返回值:Vec2](#5.5 返回值:Vec2)

六、函数体逻辑:自定义"加法规则"

七、真实调用过程再走一遍(含链式加法)

[7.1 标准过程](#7.1 标准过程)

1)代码:

2)编译器理解为:

3)调用过程:

[7.2 链式加法](#7.2 链式加法)

1)代码:

2)翻译过程:

3)解释:

八、和普通函数重载的关系

[8.1 运算符重载本质上就是"函数重载语法糖"](#8.1 运算符重载本质上就是“函数重载语法糖”)

[8.2 成员版本 vs 非成员版本(全局函数)](#8.2 成员版本 vs 非成员版本(全局函数))

1)成员版本:

2)非成员版本

3)调用

4)差别

九、运算符重载的一些面试问题

十、总结


前言

在之前的学习中,已经详细的讲解了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,有两个成员:xy

  • 为这个类型 重载了 + 运算符,让你可以写:

    cpp 复制代码
    Vec2 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 作为参数传进去"

  • 就像你调用任何成员函数一样:

    cpp 复制代码
    object.function(parameter)

它跟运算符一点关系也没有。

一句话:想用 a + b 这种写法,就必须写 operator+,不叫这个名字就不算运算符重载。


四、a + b 是怎么关联到 thisother 的?

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)含义

这里的参数写法非常典型,含义分三层:

  1. &引用

    • 不拷贝对象,直接绑定到传进来的那个对象 b

    • 效率高,尤其是对象比较大时

  2. const不能通过这个引用去修改对象

    • "const 确定了 other 引用的值不能改变吗"

    • 在函数体里,下面这样做是非法的:

      cpp 复制代码
      other.x = 10; // ❌ 编译不过
  3. 合起来 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,而不去修改 ab 自身。

小结:

  • 参数前的 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)调用过程:

  1. 生成对象 a(1, 2)b(3, 4)

  2. a.operator+(b)

    • this->x = 1this->y = 2

    • other.x = 3other.y = 4

  3. 计算并返回 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

  • 非成员版:两边都作为参数传入,有时候对"对称运算符"(如 ==、+)会更灵活


九、运算符重载的一些面试问题

  1. 不能发明新运算符

    只能重载已有的**:+ - * / [] () == << >>** 等。

  2. 重载不会改变优先级和结合性
    a + b * c 还是先乘后加,重载不影响运算符优先级。

  3. 最好保证语义直观
    + 就应是"加法",不要拿它实现奇怪行为(容易坑队友)。

  4. const 正确性很重要

    • 参数用 const T&:不改参数

    • 成员函数后加 const:不改当前对象

    这两个在写类库/八股题时是加分项


十、总结

  • a + b 在成员运算符重载形式下,会被翻译成 a.operator+(b)

    • athis(隐式参数)

    • bother(显式参数)

  • const Vec2& other 表示:按引用接收参数,不能在函数里改它

  • 函数末尾的 const 表示:这个函数不会修改当前对象(this)

  • 写成 Vec2 operator+(...) 是因为:

    • 前面的 Vec2 是返回值类型

    • operator+ 是一个特殊命名的函数名,用于告诉编译器"这是 + 运算符的重载"。

  • 运算符重载本质上是普通函数 + 特定命名 + 语法糖逻辑完全是你在函数体里定义的。

相关推荐
ALex_zry4 小时前
C++中经典的定时器库与实现方式
开发语言·c++
槿花Hibiscus4 小时前
C++基础:session实现和http server类最终组装
服务器·c++·http·muduo
仰泳的熊猫4 小时前
1116 Come on! Let‘s C
数据结构·c++·算法·pat考试
千疑千寻~4 小时前
【QML】C++访问QML控件
c++·qml
June`5 小时前
C++11(四):特殊类与单例模式设计精要
开发语言·c++
明月别枝惊鹊丶5 小时前
【C++】GESP 三级手册
java·开发语言·c++
ZouZou老师5 小时前
C++设计模式之责任链模式:以家具生产为例
c++·设计模式·责任链模式
lynnlovemin5 小时前
从暴力到高效:C++ 算法优化实战 —— 排序与双指针篇
java·c++·算法
慕容青峰6 小时前
牛客小白月赛 103 C 题题解
c++·算法·sublime text