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 应用程序。它使得思维导图变得简单,你可以托管并创建您自己的思维导图。与您的团队分享您的思维导图会议并在思维导图上进行协作。 软件特点: 创建࿱…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...
