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。 首先,你可以使用以…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...

《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...