C++ 运算符重载为成员函数
运算符重载实质上就是函数重载,重载为成员函数,他就可以自由访问本类的数据成员。实际使用时,总是通过该类的某个对象来访问重载的运算符。
如果是双目运算符,左操作数是对象本身的数据,由this指针指出,右操作数则需要通过运算符重载函数的参数表来传递;如果是单目运算符,操作数由对象的this指针给出,就不再需要任何参数。
(1)双目运算符的重载
对于双目运算符B,如果要重载为类的成员函数,使之能够实现表达式a B c ,其中a1是A类的对象,则应当把B重载为A类的成员函数,该函数只有一个形参,形参类型为c所属的类型。经过重载之后,表达式a B c 就相当于调用a.operator B(c)。
(2)单目运算符的重载
对于前置单目运算符U,如“-”(负号)等,如果要重载为类的成员函数,用来实现表达式U a,其中a为A类对象,那么U应当重载为A类的成员函数,函数没有形参。经过重载之后,表达式U a就相当于调用a.operator U()
对于后置运算符“++”和“–”来说,如果将它们重载为类的成员函数,用来实现表达式a++或者a--,其中a为A类对象,那么运算符就应当重载为A类的成员函数,这时函数要带有一个整型(int)形参。重载之后,表达式a++和a--就相当于调用a.operator++(0)和a.operator--(0)。这里的int类型的参数在运算中不起任何作用,只是用于区别后置++、–和前置++、–。
【例1】两个对象相加的实现体,即两个对象相加的原理。就是把两个对象中的数据成员依次进行相加。
class A
{
public:A(int i = 0, int j = 0, int k = 0) :m_i(i), m_j(j), m_k(k) {}int GetI()const{return m_i;}int GetJ()const{return m_j;}void Add(A& s){cout <<"("<< this->m_i + s.m_i << "," << this->m_j + s.m_j << "," << this->m_k + s.m_k<<")"<<endl;}private:int m_i;int m_j;int m_k;
};
void main()
{A a(2, 5, 7);A b(5, 7, 9);a.Add(b); //a+b
}
运行结果:

【例2】两个对象相乘的实现体,即两个对象相乘的原理。就是把两个对象中的数据成员依次进行相乘。
class A
{
public:A(int i = 0, int j = 0, int k = 0) :m_i(i), m_j(j), m_k(k) {}int GetI()const{return m_i;}int GetJ()const{return m_j;}void fn(A& s){cout << "(" << this->m_i * s.m_i << "," << this->m_j * s.m_j << "," << this->m_k * s.m_k << ")" << endl;}
private:int m_i;int m_j;int m_k;
};
void main()
{A a(2, 5, 7);A b(5, 7, 9);a.fn(b); //a * b}
运行结果:

以上两个个例子中,在执行Add函数a.Add(b);或者fn函数a.fn(b); 之前,在执行结果还没有出来的情况下,我们是不知道这两个函数到底是干什么的,这导致程序的可读性不好。虽然上面两个例子中通过函数的调用实现了我们所需要实现的功能,但是这样的写法不如直接写成运算符可以直观的表达出我们要现实的功能是什么。所以引出运算符重载。
运算符重载的原因:
①想让当前的对象像基本数据类型去操作。
②把对象的运算写成运算符的形式比写成函数调用的形式可读性更强。
【例3】把运算符“+”重载为成员函数
class A
{
public:A(int i = 0) :m_i(i) {}A operator+(A& s){cout << "调用函数operator +()" << endl;return this->m_i + s.m_i;//把A类中的m_i和B类中的m_i相加,this指针指向当前对象a中的数据成员m_i的地址//此处返回值为int型,是因为构造函数可以进行类型转换}void print(){cout << m_i << endl;}
private:int m_i;
};
int main()
{A a(5);A b(6);//a + b;//相当于a.operator+(b) //+(a.b)(a + b).print();/*遇到+,先看类中有没有重载加法运算符,如果重载了,去调用这个+的重载函数,把第一个操作数a当作this指针传给这个重载函数,把右操作数b当作实参传给+的重载函数的形参*/A c;c = a.operator+(b);c.print();return 0;
}
运行结果:

结果分析:
在程序中,遇到“+”,先看此处的“+”是不是加法运算符重载,如果重载了,去调用这个“+”的重载函数,在上述程序,主函数中遇到的a+b,这里的“+”是加法运算符重载,所以去调用A operator+(A& s)重载函数,把第一个操作数a当作this指针传给这个重载函数,把右操作数b当作实参传给这个重载函数的形参A& s。在重载函数A operator+(A& s)的函数体内将A类对象a中的m_i和B类对象b中的m_i相加的值返回给A类的构造函数的形参,然后通过初始化列表给A类的数据成员m_i进行赋值为A类中对象m_i的值和B类对象m_i的值相加的结果。然后用这个相加后的对象去调用print函数,输出相加的结果。
因为运算符重载的实质为函数重载,所以可以把a+b;写为a.operator+(b);这两种写法完全相同。
减法运算符“-”的重载与加法运算符“+”的重载同理。
【例4】默认赋值运算符重载函数
class A
{
public:A(int i = 0) :m_i(i) {}void print(){cout << m_i << endl;}
private:int m_i;
};
int main()
{A a(5);A b(6);(a = b).print();return 0;
}
运行结果:

结果分析:
我们从程序中可以看出当前运算符“=”并没有重载,但是结果却没错,说明在类中给了一个默认的赋值运算符重载函数。默认的赋值运算符重载函数就是把当前的右边对象的数据成员的值依次赋值给左边对象的数据成员。这里的默认赋值重载函数是浅赋值。如果把这个默认赋值运算符重载函数写出来,就是这样:
A& operator=(const A& s)
{if(this==&s)//判断自赋值return *this;m_i=s.m_i;return *this;}
所以 (a = b).print();相当于是a.operator=(b),把a当作this指针传给这个重载函数,把b当作实参传给这个重载函数的形参。上面这个默认的赋值运算符重载函数的返回类型为引用类型,是因为如果使用值类型返回就会产生拷贝构造函数,比较麻烦,而这里由当前运算符组成的表达式可以放在=的左边,它具有相应的内存空间,所以使用引用作为默认的赋值运算符重载函数的返回类型。所以,最后的 return *this;返回的就是当前对象a的数据成员m_i的值。
【例5】单目运算符“++”重载为成员函数。
class A
{
public:A(int i = 0) :m_i(i) {}void print(){cout << m_i << endl;}A operator++(int) //为了实现++的重载,语法规定,在后++的时候,参数里面写int,没有实际的意义,不用传参{cout << "调用函数operator++" << endl;return m_i++;}A& operator++(){cout << "调用函数++operator" << endl;m_i = m_i + 1;return *this;}
private:int m_i;
};void main()
{A a(6);A b(3);A c(20);//后置++cout << "(a++)表达式的值:"<<endl;(a++).print();//相当于a.++() //a++表达式的值是a没加以前的值6 a的值是a加过1之后的值7,最终返回的是表达式的值//(a++)这个表达式在执行过程中有两个结果cout << "a的值:" << endl;a.print();//前置++ cout << "(++b)表达式的值:" << endl;(++b).print(); //b.++() ++b表达式的值是b加过1之后的值,b的值也是b加过1之后的值//因为++b表达式的值和b的值是相同的,所以没有必要给++b这个表达式开辟空间,直接从b的内存单元中将这个值取出来,所以返回类型可以不用值类型,而是使用引用的返回类型cout << "b的值:" << endl;b.print();}
运行结果:

结果分析:
①语法规定,在后置++的时候,参数里面写int,没有实际的意义,不用传参,它的目的是为了与前置++构成函数重载。
②后置++:(a++)表达式的值是a没加以前的值,a的值变为了a+1以后的值,所以后置++表达式有两个不同的值,但是最终返回的是表达式的值,因此,对于将后置++运算符重载为成员函数时的返回类型为值类型。
③前置++ :(++b)表达式的值和b的值一样,都是b+1以后的值,所以前置++表达式的值只有一个,因为++b表达式的值和b的值是相同的,所以没有必要给++b这个表达式开辟空间,直接从b的内存单元中将这个值取出来,所以返回类型可以不用值类型,而是使用引用的返回类型。
相关文章:
C++ 运算符重载为成员函数
运算符重载实质上就是函数重载,重载为成员函数,他就可以自由访问本类的数据成员。实际使用时,总是通过该类的某个对象来访问重载的运算符。 如果是双目运算符,左操作数是对象本身的数据,由this指针指出,右…...
51单片机程序烧录教程
STC烧录步骤 (1)STC单片机烧录方式采用串口进行烧录程序,连接的方式如下图: (2)所以需要先确保USB转串口驱动是识别到,且驱动运行正常;是否可通过电脑的设备管理器查看驱动是否正常…...
Linux C++ 链接数据库并对数据库进行一些简单的操作
一.引言(写在之前) 在我们进行网络业务代码书写的时候,我们总是避免对产生的数据进行增删改查,为此,本小博主在这里简历分享一下自己在Linux中C语言与数据之间交互的代码的入门介绍。 二.代码书写以及一些变量和函数的…...
Linux进程间通信--msgsnd函数的作用
msgsnd函数用于将消息发送到消息队列中。它的原型如下: int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数解释: msqid:消息队列标识符,由msgget函数返回。msgp:指向要发送的消息的指针&…...
P1629 邮递员送信(最短路)(内附封面)
邮递员送信 题目描述 有一个邮递员要送东西,邮局在节点 1 1 1。他总共要送 n − 1 n-1 n−1 样东西,其目的地分别是节点 2 2 2 到节点 n n n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m m m 条道路。这…...
网络安全--原型链污染
目录 1.什么是原型链污染 2.原型链三属性 1)prototype 2)constructor 3)__proto__ 4)原型链三属性之间关系 3.JavaScript原型链继承 1)分析 2)总结 3)运行结果 4.原型链污染简单实验 1)实验一 2࿰…...
Harbor企业镜像仓库部署
目录 一、Harbor 架构构成 二、部署harbor环境 1、安装docker-ce(所有主机) 2、阿里云镜像加速器 3、部署Docker Compose 服务 4、部署 Harbor 服务 5、启动并安装 Harbor 6、创建一个新项目 三、客户端上传镜像 1、在 Docker 客户端配置操作如下…...
【AI】《动手学-深度学习-PyTorch版》笔记(十一):分类问题-softmax回归
AI学习目录汇总 1、线性回归和softmax回归的区别 1)连续值与离散值 线性回归模型,适用于输出为连续值的情景。 softmax回归模型,适用于输出为离散值的情景。例如图像类别,就需要对离散值进行预测。softmax回归模型引入了softmax运算,使输出更适合离散值的预测和训练。 …...
【排序算法略解】(十种排序的稳定性,时间复杂度以及实现思想)(含代码)(完工于2023.8.3)
文章目录 1、冒泡排序/选择排序/插入排序冒泡排序(Bubble Sort)选择排序(Selection Sort)插入排序(Insertion Sort) 2、希尔排序(Shells Sort)3、快速排序(Quick Sort)4、堆排序(Heap Sort)5、归并排序(Merge Sort)6、桶排序/计数排序/基数排序桶排序(Bucket sort)计数排序(Cou…...
学编程实用网站
牛客网:面试刷题和面试经验分享的网站牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网 (nowcoder.com)https://www.nowcoder.com/ 慕课网:在线学习 慕课网-程序员的梦工厂 (imooc.com)https://www.imooc.com/ …...
Camunda 7.x 系列【5】 员工请假流程模型
有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 2.7.9 本系列Camunda 版本 7.19.0 源码地址:https://gitee.com/pearl-organization/camunda-study-demo 文章目录 1. 概述2. 模型设计2.1 基础配置2.2 启动事件2.3 填写请假单2.4 上级领导审批3.5 经理审批3…...
【C++从0到王者】第十七站:手把手教你写一个stack和queue及deque的底层原理
文章目录 一、stack1.利用适配器2.栈的实现 二、queue三、deque1.deque介绍2.deque的接口3.deque的基本使用4.deque的效率5.deque的原理 一、stack 1.利用适配器 我们不可能写了一份数组栈以后,还要在手写一个链式栈,这样显得太冗余了。于是我们可以利…...
ffmpeg.c源码与函数关系分析
介绍 FFmpeg 是一个可以处理音视频的软件,功能非常强大,主要包括,编解码转换,封装格式转换,滤镜特效。FFmpeg支持各种网络协议,支持 RTMP ,RTSP,HLS 等高层协议的推拉流,…...
GD32F103待机模式与唤醒
GD32F103待机模式与唤醒,本程序使用RTC报警唤醒。 电源管理单元有3种省电模式:睡眠模式,深度睡眠模式和待机模式; 进入待机模式的步骤如下: 若需要RTC闹钟输出,则需要将TAMPER-RTC映射到PC13引脚; 若需要LXTAL晶振32.768KHz&…...
【Linux初阶】基础IO - 动静态库 | 初识、生成、链接、加载
🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux初阶】 ✒️✒️本篇内容:动静态库初识,库的含义,静态库的生成与链接,gcc/g默认链接方式,…...
为Git仓库设置签名信息
前言 在首次使用git版本库或创建新的仓库时,需要为其仓库设定管理员和管理员邮箱。 在为仓库添加管理员和邮箱地址时,有以下两种情况: (1)全局模式:首次创建,后面做为默认使用,对当…...
iOS开发Swift开发UI页面链式调用库推荐
首页链接 https://github.com/zhiguangqiao/ChainableUIKit 安装方法 pod ChainableUIKit调用片段 UIButton import ChainableUIKitprivate let button UIButton().chain.setTitleColor(.init(hex: "#9583EB"), state: .normal).setTitle("全部视频",…...
ClickHouse SQL与引擎--基本使用(一)
1.查看所有的数据库 show databases; 2.创建库 CREATE DATABASE zabbix ENGINE Ordinary; ATTACH DATABASE ck_test ENGINE Ordinary;3.创建本地表 CREATE TABLE IF NOT EXISTS test01(id UInt64,name String,time UInt64,age UInt8,flag UInt8 ) ENGINE MergeTree PARTI…...
2023-08-07力扣今日七题-好题
链接: 剑指 Offer 11. 旋转数组的最小数字 154. 寻找旋转排序数组中的最小值 II 题意: 找一个数组里的最小值,这个数组是有非递减数组旋转而来的,旋转n次表示把前n个数移动到数组末尾 解: 很有趣的二分ÿ…...
支持多用户协同的思维导图TeamMapper
什么是 TeamMapper ? TeamMapper 是基于 Mindmapp 开发的用于绘制思维导图的 Web 应用程序。它使得思维导图变得简单,你可以托管并创建您自己的思维导图。与您的团队分享您的思维导图会议并在思维导图上进行协作。 软件特点: 创建࿱…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
