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

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++ 运算符重载为成员函数

运算符重载实质上就是函数重载&#xff0c;重载为成员函数&#xff0c;他就可以自由访问本类的数据成员。实际使用时&#xff0c;总是通过该类的某个对象来访问重载的运算符。 如果是双目运算符&#xff0c;左操作数是对象本身的数据&#xff0c;由this指针指出&#xff0c;右…...

51单片机程序烧录教程

STC烧录步骤 &#xff08;1&#xff09;STC单片机烧录方式采用串口进行烧录程序&#xff0c;连接的方式如下图&#xff1a; &#xff08;2&#xff09;所以需要先确保USB转串口驱动是识别到&#xff0c;且驱动运行正常&#xff1b;是否可通过电脑的设备管理器查看驱动是否正常…...

Linux C++ 链接数据库并对数据库进行一些简单的操作

一.引言&#xff08;写在之前&#xff09; 在我们进行网络业务代码书写的时候&#xff0c;我们总是避免对产生的数据进行增删改查&#xff0c;为此&#xff0c;本小博主在这里简历分享一下自己在Linux中C语言与数据之间交互的代码的入门介绍。 二.代码书写以及一些变量和函数的…...

Linux进程间通信--msgsnd函数的作用

msgsnd函数用于将消息发送到消息队列中。它的原型如下&#xff1a; int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数解释&#xff1a; msqid&#xff1a;消息队列标识符&#xff0c;由msgget函数返回。msgp&#xff1a;指向要发送的消息的指针&…...

P1629 邮递员送信(最短路)(内附封面)

邮递员送信 题目描述 有一个邮递员要送东西&#xff0c;邮局在节点 1 1 1。他总共要送 n − 1 n-1 n−1 样东西&#xff0c;其目的地分别是节点 2 2 2 到节点 n n n。由于这个城市的交通比较繁忙&#xff0c;因此所有的道路都是单行的&#xff0c;共有 m m m 条道路。这…...

网络安全--原型链污染

目录 1.什么是原型链污染 2.原型链三属性 1&#xff09;prototype 2)constructor 3)__proto__ 4&#xff09;原型链三属性之间关系 3.JavaScript原型链继承 1&#xff09;分析 2&#xff09;总结 3)运行结果 4.原型链污染简单实验 1&#xff09;实验一 2&#xff0…...

Harbor企业镜像仓库部署

目录 一、Harbor 架构构成 二、部署harbor环境 1、安装docker-ce&#xff08;所有主机&#xff09; 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…...

学编程实用网站

牛客网&#xff1a;面试刷题和面试经验分享的网站牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推&#xff0c;求职就业一站解决_牛客网 (nowcoder.com)https://www.nowcoder.com/ 慕课网&#xff1a;在线学习 慕课网-程序员的梦工厂 (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.利用适配器 我们不可能写了一份数组栈以后&#xff0c;还要在手写一个链式栈&#xff0c;这样显得太冗余了。于是我们可以利…...

ffmpeg.c源码与函数关系分析

介绍 FFmpeg 是一个可以处理音视频的软件&#xff0c;功能非常强大&#xff0c;主要包括&#xff0c;编解码转换&#xff0c;封装格式转换&#xff0c;滤镜特效。FFmpeg支持各种网络协议&#xff0c;支持 RTMP &#xff0c;RTSP&#xff0c;HLS 等高层协议的推拉流&#xff0c…...

GD32F103待机模式与唤醒

GD32F103待机模式与唤醒&#xff0c;本程序使用RTC报警唤醒。 电源管理单元有3种省电模式:睡眠模式,深度睡眠模式和待机模式&#xff1b; 进入待机模式的步骤如下&#xff1a; 若需要RTC闹钟输出&#xff0c;则需要将TAMPER-RTC映射到PC13引脚; 若需要LXTAL晶振32.768KHz&…...

【Linux初阶】基础IO - 动静态库 | 初识、生成、链接、加载

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【Linux初阶】 ✒️✒️本篇内容&#xff1a;动静态库初识&#xff0c;库的含义&#xff0c;静态库的生成与链接&#xff0c;gcc/g默认链接方式&#xff0c…...

为Git仓库设置签名信息

前言 在首次使用git版本库或创建新的仓库时&#xff0c;需要为其仓库设定管理员和管理员邮箱。 在为仓库添加管理员和邮箱地址时&#xff0c;有以下两种情况&#xff1a; &#xff08;1&#xff09;全局模式&#xff1a;首次创建&#xff0c;后面做为默认使用&#xff0c;对当…...

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力扣今日七题-好题

链接&#xff1a; 剑指 Offer 11. 旋转数组的最小数字 154. 寻找旋转排序数组中的最小值 II 题意&#xff1a; 找一个数组里的最小值&#xff0c;这个数组是有非递减数组旋转而来的&#xff0c;旋转n次表示把前n个数移动到数组末尾 解&#xff1a; 很有趣的二分&#xff…...

支持多用户协同的思维导图TeamMapper

什么是 TeamMapper &#xff1f; TeamMapper 是基于 Mindmapp 开发的用于绘制思维导图的 Web 应用程序。它使得思维导图变得简单&#xff0c;你可以托管并创建您自己的思维导图。与您的团队分享您的思维导图会议并在思维导图上进行协作。 软件特点&#xff1a; 创建&#xff1…...

【Vue】Parsing error: No Babel config file detected for ... vue

报错 Parsing error: No Babel config file detected for E:\Study\Vue网站\实现防篡改的水印\demo02\src\App.vue. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files.             …...

2023-08-07力扣今日五题

链接&#xff1a; 剑指 Offer 53 - II. 0&#xff5e;n-1中缺失的数字 题意&#xff1a; 如题 解&#xff1a; 长度n的递增数组里&#xff0c;要找0到n中没出现的那个数字&#xff0c;那么出现的下标是0到n-1&#xff0c;一一对应即可&#xff0c;都出现了就是n没有 实际…...

ETHERCAT转PROFIBUS连接到300plc的配置方法

由于捷米JM-DP-ECT&#xff0c;是自主研发的一款PROFIBUS从站功能的通讯网关&#xff0c;它的主要功能是将ETHERCAT设备接入到PROFIBUS网络中生产环境比较复杂有多个设备采用不同的协议这极大的阻碍了&#xff0c;各个设备的数据互通。 JM-DP-ECT这个小小的网关可不简单&#x…...

Spring Boot配置文件与日志文件

1. Spring Boot 配置文件 我们知道, 当我们创建一个Spring Boot项目之后, 就已经有了配置文件存在于目录结构中. 1. 配置文件作用 整个项目中所有重要的数据都是在配置文件中配置的&#xff0c;比如: 数据库的连接信息 (包含用户名和密码的设置) ;项目的启动端口;第三方系统的调…...

可解释性分析的一些类别(草稿)(视觉)

目录 1.交互性解释 2. 本身具有解释性的模型 3.如何将可解释性分析应用到生成模型 参考文献 视觉领域从2020年开始可以分为两块&#xff0c;一个是图像分类&#xff0c;一个是图像生成。 图像分类&#xff1a;输入一张图片&#xff0c;输出语义标签&#xff0c;就是这张图…...

HTTPS-RSA握手

RSA握手过程 HTTPS采用了公钥加密和对称加密结合的方式进行数据加密和解密 RSA握手是HTTPS连接建立过程中的一个关键步骤&#xff0c;用于确保通信双方的身份验证和生成对称加密所需的密钥 通过RSA握手过程&#xff0c;客户端和服务器可以协商出一个共享的对称密钥&#xff0c;…...

bigemap国土管理行业应用

由于国营企业单位&#xff0c;管理土地&#xff0c;必须要有这样的软件套图 客户之前用的谷歌&#xff0c;后来不能访问了&#xff0c;通过其他途径搜索到我们 客户使用软件一般都用于套坐标以及空间规划图&#xff0c;方便于项目选址和居民建房报建在卫星图上找到用地范围&am…...

深入探索 Splashtop Enterprise 的潜力

在当今高度技术化的环境中&#xff0c;远程访问解决方案已成为无数组织的支柱。远程访问解决方案缩短了员工与工作之间的地理差距&#xff0c;提高了工作的效率和灵活性&#xff0c;促进形成了无缝的工作体验。在众多远程访问解决方案中&#xff0c;Splashtop Enterprise 作为远…...

创建型模式-单例模式

文章目录 一、创建型模式1. 单例设计模式1.1 单例模式的结构1.2 单例模式的实现&#xff08;1&#xff09;饿汉式-方式1&#xff08;静态变量方式&#xff09;&#xff08;2&#xff09;饿汉式-方式2&#xff08;静态代码块方式&#xff09;&#xff08;3&#xff09;懒汉式-方…...

2. Linux安装Git

yum安装 查看版本 版本太低&#xff0c;所以我们采用自己上传编译的方式进行 删除已安装的git yum remove git 下载最新安装包&#xff0c;并上传到服务器文件夹下 上传&#xff0c;解压 5.安装编译需要的依赖 yum install curl-devel expat-devel gettext-devel openssl-…...