c++重载操作符
支持重载操作符是c++的一个特性,先不管好不好用,这起码能让它看起来比其他语言NB很多,但真正了解重载操作符后,就会发现这个特性...就这?本文分两个部分
- 重载操作符简介和使用——适用新手
- 重载操作符的原理和sao操作——适用装杯选手
1 简介 & 使用
c++支持重载的操作符有
算术操作符 | +、-、*、/、% |
关系操作符 | ==、!=、>、<、>=、<= |
逻辑操作符 | !、&&、|| |
位操作符 | ~、&、|、^、<<、>> |
赋值操作符 | =、+=、-=、*=、/=、%=、&=、|=、^=、>>=、<<= |
下标操作符 | [] |
函数调用操作符 | () |
成员访问操作符 | -> |
指针操作符 | *(解引用)、&(取地址) |
逗号操作符 | , |
这些操作符按照操作数个数不同分为单目操作符、双目操作符、多目操作符
单目操作符 | !、~、->、*(解引用)、&(取地址) |
双目操作符 | 其他 |
多目操作符 | () |
为什么要按这个分类?别急,继续看...
用法
重载操作符实际上就是重新定义操作符的行为函数,不过这里需要用到一个关键字operator
。大多数操作符有两种重载方式
- 类成员函数重载
- 全局函数重载
例如
// 成员函数重载Point类的"+"操作符和"~"操作符 —— 定义在类内部
struct Point {Point operator+(const Point& oth) const { ... }Point operator~() const { ... }
};// 全局函数重载Point类的"+"操作符和"~"操作符 —— 定义在类外部
Point operator+(const Point& self, const Point& oth) { ... }
Point operator~(const Point& self) { ... }
一些限制
有的程序员不喜欢使用重载操作符,因为它的特性实在难以琢磨。但实际上它只是在定义函数的基础上又一些限制
- 基本数据类型:只能通过全局函数重载操作符。因为基本数据类型是语言内置的,无法自定义。
- 自定义类型(这也是最通用的用法)
- 所有支持重载的操作符都可以通过类成员函数重载
- 大部分支持重载的操作符都可以通过全局函数重载,有3个例外:
()
、[]
、->
- 每个操作符重载时形参个数都是固定的,按照单目、双目、多目分类,形参个数要求如下
单目操作符 | 双目操作符 | 多目操作符 | |
全局函数 | 1 | 2 | - |
类成员函数 | 0 | 1 | 0个或多个 |
以上内容,足够正确使用重载操作符。但有些同学会觉得很难理解和正确使用,下面一起理解一下重载操作符的本质,理解本质之后再回头来看就会发现重载操作符原来...就这?
2 重载操作符的本质
重载操作符本质上是特殊的函数。在c++中,函数具有以下形式
返回值 函数名 (形参列表) { 函数体 }
可以看到,函数由四个部分组成:返回值、函数名、形参列表、函数体。重载操作符本质上也是函数,只是在 函数名、形参列表 两部分具有特殊性,另外 调用方式 也很特殊。
函数名
重载操作符的函数名是由operator
关键字和操作符符号组成的,例如 operator+、
operator!
等等。
形参列表
形参列表的参数数量是固定的,具体见下面的表格
单目操作符 | 双目操作符 | 操作符-特殊 | |
全局函数 | 1 (self) | 2 (self, 任意类型) | - |
类成员函数 | 0 | 1 (任意类型) | 0个或多个 |
一个没用的小知识
大家可能已经发现了,对于同一个操作符而言全局函数重载总是比类成员函数重载多一个参数,这个多出来的参数有两个特点:
- 一定是全局函数的第一个形参。
- 类型一定是重载操作符的目标类型。例如
成员函数重载:
Point operator+(const Point& oth) const { ... }
全局函数重载:
Point operator+(const Point& self, const Point& oth) { ... }
这里隐藏了一个成员函数的秘密:在c++中,成员函数默认第一个参数是this指针,只不过写法上忽略了。大家感兴趣的话可以研究下成员函数的汇编码,其中的奥秘就一目了然了。熟悉python语法的同学应该能很容易理解,python的类成员函数必须把第一个参数写成self,这样才能在函数体内访问成员变量。
调用方式
操作符的使用和函数调用有直观上的差别,如何使用操作符大家应该都很熟悉,这里就不举例子了。值得一提的是操作符的使用本质上还是函数调用。举个例子,用全局函数重载"+"
操作符
struct Point {Point(int x, int y) : x(x), y(y) { }int x;int y;
};// 重载Point的“+”操作符
Point operator+(const Point& self, const Point& oth) { return Point(self.x + oth.x, self.y + oth.y); }int main() {Point p1(20, 60);Point p2(2, 5);Point pAdd = p1 + p2; // 使用Point的“+”操作符
}
上面这段代码的汇编代码如下(为了方便大家能抓住重点,对汇编码做了精简)
Point::Point(int, int) [base object constructor]:...ret
operator+(Point const&, Point const&):...ret
main:...mov rsi, rdxmov rdi, raxcall operator+(Point const&, Point const&)...ret
可以看到,编译器把Point pAdd = p1 + p2;
这句c++代码编译成了call operator+(Point const&, Point const&)
,也就是调用函数operator+(Point const&, Point const&)
。
看到这里,大家脑子里会不会闪过一个大胆的想法——在c++代码中直接调用函数operator+(Point const&, Point const&)
会怎么样?就像...
...Point pAdd = operator+(p1, p2); // Point pAdd = p1 + p2;
...
然后我们会发现代码竟然可以 正!常!运!行!而且对应的汇编代码也一!模!一!样!所以,操作符也可以通过函数掉调用的方式使用。
前面研究的是全局函数重载的行为,那么成员函数重载呢?我们一起来看看
struct Point {Point(int x, int y) : x(x), y(y) {}// 重载Point的“+”操作符Point operator+(const Point& oth) const { return Point(x + oth.x, y + oth.y); }int x;int y;
};int main() {Point p1(20, 60);Point p2(2, 5);Point pAdd = p1 + p2; // 使用Point的“+”操作符
}
对应的汇编代码
Point::Point(int, int) [base object constructor]:...ret
Point::operator+(Point const&) const:...ret
main:...mov rsi, rdxmov rdi, raxcall Point::operator+(Point const&) const...ret
编译器把Point pAdd = p1 + p2;
这句c++代码编译成了call Point::operator+(Point const&) const
。不难发现,全局函数重载和成员函数重载对应的汇编代码的operator+
符号不一样:
- 形参列表不同。全局函数有两个形参,成员函数有一个形参。
- 域前缀不同。全局函数没有域前缀,类成员函数汇编后携带了域信息
Point
。
成员函数重载操作符也可以像函数调用一样使用,只不过需要遵守成员函数的调用规则
...Point pAdd = p1.operator+(p2); // Point pAdd = p1 + p2;
...
下面做个简单对比
全局函数重载 | 类成员函数重载 | |
c++代码 | | |
汇编代码 |
|
|
函数式调用 |
|
|
以上就是重载操作符相对于普通函数的特殊所在,除了这几个特殊点其他方面没有任何不同。在使用的时候我们可以对返回值、形参类型、函数体为!所!欲!为!
严重警告
- 尽管规则允许我们直接调用重载操作符,但尽量不要这样做,因为这样做的话c++的NB程度会锐减,而且一定会有人在看代码的时候骂你。
- 尽管规则上可以为所欲为,还是建议各位保持冷静,玩玩儿可以千万不要在项目中写出太超越道德上限的代码。像这样
struct Cat { ... };
struct Dog { ... };Dog operator+(const Cat& self, const Cat& oth) {...return Dog();
}
一只猫加另一只猫,得到一条狗?
相关文章:
c++重载操作符
支持重载操作符是c的一个特性,先不管好不好用,这起码能让它看起来比其他语言NB很多,但真正了解重载操作符后,就会发现这个特性...就这?本文分两个部分 重载操作符简介和使用——适用新手重载操作符的原理和sao操作——…...

C# 如何读取Excel文件
当处理Excel文件时,从中读取数据是一个常见的需求。通过读取Excel数据,可以获取电子表格中包含的信息,并在其他应用程序或编程环境中使用这些数据进行进一步的处理和分析。本文将分享一个使用免费库来实现C#中读取Excel数据的方法。具体如下&…...
Vue2面试题:说一下对vuex的理解?
五种状态: state: 存储公共数据 this.$store.state mutations:同步操作,改变store的数据 this.$store.commit() actions: 异步操作,让mutations中的方法能在异步操作中起作用 this.$store.dispatch() getters: 计算属性 th…...

elasticsearch系列五:集群的备份与恢复
概述 前几篇咱们讲了es的语法、存储的优化、常规运维等等,今天咱们看下如何备份数据和恢复数据。 在传统的关系型数据库中我们有多种备份方式,常见有热备、冷备、全量定时增量备份、通过开发程序备份等等,其实在es中是一样的。 官方建议采用s…...

【Elasticsearch源码】 分片恢复分析
带着疑问学源码,第七篇:Elasticsearch 分片恢复分析 代码分析基于:https://github.com/jiankunking/elasticsearch Elasticsearch 8.0.0-SNAPSHOT 目的 在看源码之前先梳理一下,自己对于分片恢复的疑问点: 网上对于E…...

elasticsearch如何操作索引库里面的文档
上节介绍了索引库的CRUD,接下来操作索引库里面的文档 目录 一、添加文档 二、查询文档 三、删除文档 四、修改文档 一、添加文档 新增文档的DSL语法如下 POST /索引库名/_doc/文档id(不加id,es会自动生成) { "字段1":"值1", "字段2&q…...

opencv期末练习题(2)附带解析
图像插值与缩放 %matplotlib inline import cv2 import matplotlib.pyplot as plt def imshow(img,grayFalse,bgr_modeFalse):if gray:img cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)plt.imshow(img,cmap"gray")else:if not bgr_mode:img cv2.cvtColor(img,cv2.COLOR_B…...

【Mybatis】深入学习MyBatis:高级特性与Spring整合
🍎个人博客:个人主页 🏆个人专栏: Mybatis ⛳️ 功不唐捐,玉汝于成 目录 前言 正文 高级特性 1 一级缓存和二级缓存 一级缓存 二级缓存 2 延迟加载 5 整合Spring 1 MyBatis-Spring模块 2 事务管理 结…...
C语言与人生函数的对比,使用,参数详解
各位少年,大家好,我是博主那一脸阳光。,今天给大家分享函数的定义,和数学的函数的区别和使用 前言:C语言中的函数和数学中的函数在概念上有相似之处,但也存在显著的区别。下面对比它们的主要特点ÿ…...

机器人动力学一些笔记
动力学方程中,Q和q的关系(Q是sita) Q其实是一个向量,q(Q1,Q2,Q3,Q4,Q5,Q6)(假如6个关节) https://zhuanlan.zhihu.com/p/25789930 举个浅显易懂的例子,你在房…...

Plantuml之甘特图语法介绍(二十八)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...

Docker support for NVIDIA GPU Accelerated Computing on WSL 2
Docker support for NVIDIA GPU Accelerated Computing on WSL 2 0. 背景1. 安装 Docker Desktop2. 配置 Docker Desktop3. WLS Ubuntu 配置4. 安装 Docker-ce5. 安装 NVIDIA Container Toolkit6. 配置 Docker7. 运行一个 Sample Workload 0. 背景 今天尝试一下 NVIDIA GPU 在…...

SQL窗口函数大小详解
窗口大小 OVER 子句中的 frame_clause 选项用于指定一个滑动的窗口。窗口总是位于分区范围之内,是分区的一个子集。指定了窗口之后,分析函数不再基于分区进行计算,而是基于窗口内的数据进行计算。 指定窗口大小的语法如下: ROWS…...

C#上位机与欧姆龙PLC的通信06---- HostLink协议(FINS版)
1、介绍 对于上位机开发来说,欧姆龙PLC支持的主要的协议有Hostlink协议,FinsTcp/Udp协议,EtherNetIP协议,本项目使用Hostlink协议。 Hostlink协议是欧姆龙PLC与上位机链接的公开协议。上位机通过发送Hostlink命令,可…...

认识SpringBoot项目中的Starter
✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: 循序渐进学SpringBoot ✨特色专栏&…...

ChatGPT 4.0真的值得花钱买入吗?
性能提升: ChatGPT 4.0的推出不仅意味着更先进的技术,还代表着更强大的性能。相较于3.5,4.0在处理任务时更为高效,响应更迅速。 更智能的理解: 随着版本的升级,ChatGPT 4.0对语境的理解能力得到了进一步的…...
vue3对比vue2是怎样的
一、前言 Vue 3通过引入Composition API、升级响应式系统、优化性能等一系列的改进和升级,提供了更好的开发体验和更好的性能,使得开发者能够更方便地开发出高质量的Web应用。它在Vue.js 2的基础上进行了一系列的改进和升级,以提供更好的性能、更好的开发体验和更好的扩展性…...

openGauss学习笔记-184 openGauss 数据库运维-升级-升级验证
文章目录 openGauss学习笔记-184 openGauss 数据库运维-升级-升级验证184.1 验证项目的检查表184.2 升级版本查询184.2.1 验证步骤 184.3 检查升级数据库状态184.3.1 验证步骤 openGauss学习笔记-184 openGauss 数据库运维-升级-升级验证 本章介绍升级完成后的验证操作。给出验…...
[Verilog语言入门教程] Verilog 减法器 (半减器, 全减器, 加减共用)
依公知及经验整理,原创保护,禁止转载。 专栏 《元带你学Verilog》 <<<< 返回总目录 <<<< “逻辑设计是一门艺术,它需要创造力和想象力。” - 马克张伯伦(Mark Zwolinski) 减法器是数字电路中常见的组件,用于减去两个二进制数的和。 在Verilog中…...
预编译仓库中的 Helm Chart
背景 内网部署项目, 没法直接hlem install , 需要提前看看有哪些镜像, 拉到本地看看 要使用预编译仓库中的 Helm Chart,你可以使用 helm fetch 命令来将 Chart 下载到本地,并使用 helm template 命令来预编译该 Chart。 首先,你可以使用以…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...