当前位置: 首页 > news >正文

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++代码

Point operator+(const Point& self, const Point& oth) { ... }
struct Point {Point operator+(const Point& oth) const { ... }
};

汇编代码

operator+(Point const&, Point const&)

Point::operator+(Point const&) const

函数式调用

Point pAdd = operator+(p1, p2);

Point pAdd = p1.operator+(p2);

以上就是重载操作符相对于普通函数的特殊所在,除了这几个特殊点其他方面没有任何不同。在使用的时候我们可以对返回值形参类型函数体为!所!欲!为!

严重警告

  • 尽管规则允许我们直接调用重载操作符,但尽量不要这样做,因为这样做的话c++的NB程度会锐减,而且一定会有人在看代码的时候骂你。
  • 尽管规则上可以为所欲为,还是建议各位保持冷静,玩玩儿可以千万不要在项目中写出太超越道德上限的代码。像这样
struct Cat { ... };
struct Dog { ... };Dog operator+(const Cat& self, const Cat& oth) {...return Dog();
}

一只猫加另一只猫,得到一条狗?

相关文章:

c++重载操作符

支持重载操作符是c的一个特性&#xff0c;先不管好不好用&#xff0c;这起码能让它看起来比其他语言NB很多&#xff0c;但真正了解重载操作符后&#xff0c;就会发现这个特性...就这&#xff1f;本文分两个部分 重载操作符简介和使用——适用新手重载操作符的原理和sao操作——…...

C# 如何读取Excel文件

当处理Excel文件时&#xff0c;从中读取数据是一个常见的需求。通过读取Excel数据&#xff0c;可以获取电子表格中包含的信息&#xff0c;并在其他应用程序或编程环境中使用这些数据进行进一步的处理和分析。本文将分享一个使用免费库来实现C#中读取Excel数据的方法。具体如下&…...

Vue2面试题:说一下对vuex的理解?

五种状态&#xff1a; state: 存储公共数据 this.$store.state mutations&#xff1a;同步操作&#xff0c;改变store的数据 this.$store.commit() actions: 异步操作&#xff0c;让mutations中的方法能在异步操作中起作用 this.$store.dispatch() getters: 计算属性 th…...

elasticsearch系列五:集群的备份与恢复

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

【Elasticsearch源码】 分片恢复分析

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

elasticsearch如何操作索引库里面的文档

上节介绍了索引库的CRUD&#xff0c;接下来操作索引库里面的文档 目录 一、添加文档 二、查询文档 三、删除文档 四、修改文档 一、添加文档 新增文档的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整合

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; Mybatis ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 高级特性 1 一级缓存和二级缓存 一级缓存 二级缓存 2 延迟加载 5 整合Spring 1 MyBatis-Spring模块 2 事务管理 结…...

C语言与人生函数的对比,使用,参数详解

各位少年&#xff0c;大家好&#xff0c;我是博主那一脸阳光。&#xff0c;今天给大家分享函数的定义&#xff0c;和数学的函数的区别和使用 前言&#xff1a;C语言中的函数和数学中的函数在概念上有相似之处&#xff0c;但也存在显著的区别。下面对比它们的主要特点&#xff…...

机器人动力学一些笔记

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

Plantuml之甘特图语法介绍(二十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…...

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 选项用于指定一个滑动的窗口。窗口总是位于分区范围之内&#xff0c;是分区的一个子集。指定了窗口之后&#xff0c;分析函数不再基于分区进行计算&#xff0c;而是基于窗口内的数据进行计算。 指定窗口大小的语法如下&#xff1a; ROWS…...

C#上位机与欧姆龙PLC的通信06---- HostLink协议(FINS版)

1、介绍 对于上位机开发来说&#xff0c;欧姆龙PLC支持的主要的协议有Hostlink协议&#xff0c;FinsTcp/Udp协议&#xff0c;EtherNetIP协议&#xff0c;本项目使用Hostlink协议。 Hostlink协议是欧姆龙PLC与上位机链接的公开协议。上位机通过发送Hostlink命令&#xff0c;可…...

认识SpringBoot项目中的Starter

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 循序渐进学SpringBoot ✨特色专栏&…...

ChatGPT 4.0真的值得花钱买入吗?

性能提升&#xff1a; ChatGPT 4.0的推出不仅意味着更先进的技术&#xff0c;还代表着更强大的性能。相较于3.5&#xff0c;4.0在处理任务时更为高效&#xff0c;响应更迅速。 更智能的理解&#xff1a; 随着版本的升级&#xff0c;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&#xff0c;你可以使用 helm fetch 命令来将 Chart 下载到本地&#xff0c;并使用 helm template 命令来预编译该 Chart。 首先&#xff0c;你可以使用以…...

Python requests get和post方法发送HTTP请求

requests.get() requests.get() 方法用于发送 HTTP GET 请求。下面介绍 requests.get() 方法的常用参数&#xff1a; url: 发送请求的 URL 地址。params: URL 中的查询参数&#xff0c;可以是字典或字符串。headers: 请求头信息。可以是字典类型&#xff0c;也可以是自定义的…...

在Cadence中单独添加或删除器件与修改网络的方法

首先需要在设置中使能 ,添加或修改逻辑选项。 添加或删除器件&#xff0c;点击logic-part&#xff0c;选择需要添加或删除的器件&#xff0c;这里的器件必须是PCB中已经有的器件&#xff0c;Refdes中输入添加或删除的器件标号&#xff0c;点击Add添加。 添加完成后就会显示在R1…...

轻松调整视频时长,创意与技术的新篇章

传统的视频剪辑工具往往难以精确控制时间&#xff0c;而【媒体梦工厂】凭借其先进的算法和界面设计&#xff0c;让视频时长的调整变得简单而精确&#xff0c;助你释放无限的创意&#xff0c;用技术为你的创意插上翅膀&#xff0c;让每一秒都有意义。 所需工具&#xff1a; 一…...

树与二叉树笔记整理

摘自小红书 ## 树与二叉树 ## 排序总结...

如何自动生成 API 接口文档 - 一份详细指南

本篇文章详细教你如何使用 Apifox 的 IDEA 插件实现自动生成接口代码。好处简单总结有以下几点&#xff1a; 自动生成接口文档&#xff1a; 不用手写&#xff0c;一键点击就可以自动生成文档&#xff0c;当有更新时&#xff0c;点击一下就可以自动同步接口文档&#xff1b;代码…...

【CF比赛记录】—— Good Bye 2023(A、B、C)

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;CF比赛记录 &#x1f48c;其他专栏&#xff1a; &#x1f534;每日一题 &#x1f7e1; cf闯关练习 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓…...

MySQL:索引

MySQL官方对索引的定义为: 索引 (Index) 是帮助MySQL高效获取数据的数据结构。 提取句子主干&#xff0c;就可以得到索引的本质:索引是数据结构。 1. 什么是索引&#xff0c;索引的作用 索引是一种用于快速查询和检索数据的数据结构&#xff0c;帮助mysql提高查询效率的数据…...

CUMT--Java复习--核心类

目录 一、装箱与拆箱 二、“”与equals 三、字符串类 1、String、StringBuffer、StringBuilder的区别 2、String类 3、StringBuffer类 4、StringBuilder类 四、类与类之间关系 一、装箱与拆箱 基本类型与对应封装类之间能够自动进行转换&#xff0c;本质就是Java的自…...

Redis:原理速成+项目实战——Redis实战4(解决Redis缓存穿透、雪崩、击穿)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理项目实战——Redis实战3&#xff08;Redis缓存最佳实践&#xff08;问题解析高级实现&#xff09;&#x…...

后端开发——jdbc的学习(一)

上篇结束了Mysql数据库的基本使用&#xff0c;本篇开始对JDBC进行学习总结&#xff0c;开始先简单介绍jdbc的基本使用&#xff0c;以及简单的练习&#xff1b;后续会继续更新&#xff01;以下代码可以直接复制到idea中运行&#xff0c;便于理解和练习。 JDBC的概念 JDBC&#…...

安卓app软件开发教程/广州seo网站排名

chrome下运行编写的JavaScript代码时&#xff0c;在工具javascript控制台下有时会出现“Uncaught SyntaxError: Unexpected identifier ”的报错&#xff0c;经过我反复查看代码最后得出&#xff0c;原来是代码中缺少一个“,”&#xff08;英文逗号&#xff09;。 后经在网上查…...

衡阳公司做网站/最新疫情消息

COUNT()聚合函数&#xff0c;以及如何优化使用了该函数的查询&#xff0c;很可能是最容易被人们误解的知识点之一COUNT()的作用COUNT()是一个特殊的函数&#xff0c;有两种非常不同的作用&#xff1a;统计某个列值的数量统计行数统计列值在统计列值时&#xff0c;要求列值是非空…...

良精网站管理系统/盛大游戏优化大师

文件 > 首选项 > 用户代码片段 > 新建全局代码片段/或文件夹代码片段&#xff1a;vue-html.code-snippets 再将出现的部分替换为下面的片段 {"vue htm": {"scope": "html","prefix": "vuehtml","body":…...

网站的外链是怎么做的/桂平seo关键词优化

从计算机到手机&#xff0c;计算平台的发展不断将人类文明推向新的高峰&#xff0c;但随着移动互联网领域的开发潜力逐渐殆尽&#xff0c;越来越多的科技爱好者和开发者将目光投向了下一代计算平台——机器人。作为蕴含重大机会的领域&#xff0c;机器人产业发展却没有理想中迅…...

科技公司起名字大全免费/文军seo

入门 简单使用 <script src"../js/vue.js"></script><div id"app">{{message}}{{movies}} </div><script> const app new Vue({el:#app, //用于管理要管理的元素data:{ //定义数据 或者服务器请求数据message:你好啊,mo…...

镇江百度网站/网上宣传广告怎么做

C语言清空输入缓冲区在标准输入(stdin)情况下的使用程序1&#xff1a;//功能&#xff1a;先输入一个数字&#xff0c;再输入一个字符&#xff0c;输出hello bit#include int main(){int num 0;char ch ;scanf("%d", &num);scanf("%c", &ch);pri…...