【c++】——类和对象(中)——赋值运算符重载

作者:chlorine

专栏:c++专栏

你站在原地不动,就永远都是观众。

【学习目标】

  • 拷贝复制——赋值运算符重载

目录

🎓运算符重载的初步认识

🌈运算符重载

🌈赋值运算符重载格式 (上)

🌈operator__判断俩个日期是否相等

🎓运算符重载的深入认识

🌈赋值运算符重载格式(下)

👉拷贝构造和赋值运算符重载的区别 

👉格式(下) 

🌈默认赋值运算符重载

🌈❌重载成全局函数


🎓运算符重载的初步认识

🌈运算符重载

C++为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

  • 函数名字为:关键字operator后面接需要重载的运算符符号
  • 函数原型:返回值类型 operator操作符(参数列表)
//判断真假
bool operator==(参数列表);
//返回类型Date 运算符=
Date operator=(参数列表);
注意:
  • 不能通过连接其他符号来创建新的操作符:比如operator@

  • 重载操作符必须有一个类类型参数

  • .*  ::  sizeof  ?:  . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

🌈赋值运算符重载格式 (上)

  • 参数类型:const T&,传递引用可以提高传参效率

还有几个点我们后面会遇到问题提出的

  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回*this :要复合连续赋值的含义

对于operator关键字来对俩个数据之间的操作,我们首先来敲一段


🌈operator__判断俩个日期是否相等

利用operator来实现《判断俩个日期是否相等,如果相等返回1,如果不相等返回0》

bool operator==(const Date& d1, const Date& d2)
{return d1._year == d2._year&& d1._month == d2._month&& d1._day ==d2._day;
}

这里会发现运算符重载成全局的就需要成员变量是公有的,那么问题来了,封装性如何保证?
这里其实可以用我们后面学习的友元解决,或者干脆重载成成员函数。(友元后期会告诉)
这里既然private里的成员变量无法访问。

第一种方法:给private改成public,运行成功。 

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){cout << _year << "-" << _month << "-" << _day << endl;}
//private:int _year;int _month;int _day;
};bool operator==(const Date& d1, const Date& d2)
{return d1._year == d2._year&& d1._month == d2._month&& d1._day ==d2._day;
}int main()
{Date d1(2023, 10, 5);Date d2(2023, 11, 5);cout << (d1 == d2) << endl;d1.print();d2.print();return 0;
}

 第二种方法:将重载成成员函数,在类中。

我们放进类中充当成员函数,就一定能实现嘛?看看能不能运行成功。

参数太多,可是我们就俩个对象,为什么显示参数太多呢?
——这里就提到了我们之前说的一个重要指针——this(C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。)

所以我们上面实际上是三个参数,只是this对用户来说透明的,不能显示传递。

//d1==d2//d1就相当于this,d2相当于形参列表里面一个,所以括号里面就只能有一个参数。
// bool operator==(Date* this, const Date& d2)// 这里需要注意的是,左操作数是this,指向调用函数的对象bool operator==(const Date& x){return _year == x._year&& _month == x._month&& _day == x._day;}

这里的判断俩个日期是否相等实际上就是再比较是否d1==d2?

d1就相当于this,d2相当于形参列表里面一个,所以括号里面就只能有一个参数。

这样就运行成功了。

判断俩个日期是否相等代码如下:

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){cout << _year << "-" << _month << "-" << _day << endl;}//d1==d2//d1就相当于this,d2相当于形参列表里面一个,所以括号里面就只能有一个参数。
// bool operator==(Date* this, const Date& d2)// 这里需要注意的是,左操作数是this,指向调用函数的对象bool operator==(const Date& x){return _year == x._year&& _month == x._month&& _day == x._day;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2023, 10, 5);Date d2(2023, 11, 5);cout << (d1 == d2) << endl;/*d1.print();d2.print();*/return 0;
}

所以上面的代码实现了,运行没有问题


🎓运算符重载的深入认识

接下来我们了解了operator关键字的使用,我们接下来真正进入

赋值运算符重载

赋值运算符重载的内容——一个对象赋值给另一个对象。


🌈赋值运算符重载格式(下)

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){cout << _year << "-" << _month << "-" << _day << endl;}//拷贝构造Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//赋值运算符重载void operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;}private:int _year;int _month;int _day;
};int main()
{Date d1(2023, 10, 5);Date d2(2023, 11, 5);d1 = d2;Date d3(d1);d1.print();d3.print();return 0;
}


👉拷贝构造和赋值运算符重载的区别 

我们针对上面一段代码来进行解读。看看这段代码有没有一些毛病或者一些优化的地方。

	Date d1(2023, 10, 5);Date d2(2023, 11, 5);d1 = d2;Date d3(d1);
这俩者有啥子区别呢?或者说
哪个是拷贝构造,哪个是赋值运算符重载呢?

  • 拷贝构造:是对同类对象初始化创建对象(创建一个新对象,然后给新对象初始化)

——就如上面代码的Date d3(d1)就是拷贝构造。

  • 赋值重载运算符:一个对象赋值给另一个对象(前提俩个对象都存在)

——就如上面代码的d1=d2就是赋值重载运算符。

光标对准d1=d2赋值重载运算符但是这里还没实现 ,按下fn+f10就可以看到

d2的成员变量的值赋值给了d1,继续走,创建的新的d3对象就引入了拷贝构造函数

三者都相等了,这就是运行的过程,大家可以自己敲一下来调试,进行查看。

ps:这些都是浅拷贝(值拷贝)但是日期类都是运行浅拷贝。

让我们继续来挑这段代码的毛病吧~

int i, j, k;i = j = k = 0;

对于这种赋值运算符,c语言允许不允许这样写?——允许(连续赋值)

0先赋值给k,这个表达式有个返回值,这个返回值是k,左边的操作数就是返回值,然后继续k赋值给j,j就是返回值,以此类推.......最后i的返回值就是0。

那么日期类支持嘛?
 

	Date d4, d5;d5 = d4 = d1;

因为这里从右往左,d1赋值给d4,返回值是void,所以是无法往前走。

所以这里正确的方法是什么?

这里从右往左,d1赋值给d4,返回值应该是d4,然后d4赋值给d5

所以我们就得探究 如何让d4是返回值,而不是void?

d4=d1;

d就是d1,this就是d4的地址。this的类型是(const Date&this),所以我们的返回类型是Date.

我们需要返回d4,如何返回d4呢?

我们当初说了this不能在形参和实参的位置给,但是可以在函数内部显示给。

//赋值运算符重载//d4=d1Date operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}

👉格式(下) 

  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 返回*this :要复合连续赋值的含义

        a.(全局对象和静态对象)出了作用域都还在,用引用返回效率更高。

        b. 局部对象出了作用域都不在了,不用引用返回.

那我们的这里的*this出了作用域还在不在?

//赋值运算符重载//d4=d1Date operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}

——当然在啦

——因为首先我们要知道this是形参在栈区,出了作用域就会被销毁,那么这里是this嘛?是*this,*this是d4,d4的生命周期不再函数中,至少销毁了d4还在,*this只是一个中介而已。所以可以用引用返回。*this的别名是d4.

	//赋值运算符重载//d4=d1Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}

最后返回的是*this的别名那就是d4.

传值返回和传引用返回的区别:

传值返回:传值返回的是对象的拷贝,每一个operator赋值都是一次拷贝。(传值返回大多数是临时变量)

传引用返回:传引用返回的是*this的别名。

这样我们就可以连续赋值了。

  • 检测是否自己给自己赋值

大家有没有想过d1=d1是怎样的呢?是编译报错还是正常运行呢?

这是成功运行的。

我们来调试看看咋样?

这样也是可以的,this和&d都是自己。

如果你不想拥有自己与自己赋值,那么就可以加一个断言

Date &operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}

d1=d1

if(this!=&d) ___this是d1的地址,&d就是d的地址。如果俩者地址都相同就不用赋值了。

🌈默认赋值运算符重载

用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝
注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
默认生成赋值重载跟拷贝构造行为一样;
1.内置类型成员——值拷贝/浅拷贝  (Date)
2.自定义类型成员会去调用他的赋值重载 (MyQueue)
Stack是深拷贝,编译器自动生成的是浅拷贝。
如果我们不写赋值重载函数,编译器会不会自动生成?
class Date
{
public:Date(int year = 2003, int month = 10, int day = 5){_year = year;_month = month;_day = day;}void print(){cout << _year << "-" << _month << "-" << _day << endl;}//拷贝构造Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//赋值运算符重载//Date& operator=(const Date& d)//{//	if (this != &d)//	{//		_year = d._year;//		_month = d._month;//		_day = d._day;//	}//	return *this;//}private:int _year;int _month;int _day;
};int main()
{Date d1(2023, 10, 5);Date d2(2023, 11, 5);d1 = d2;d1.print();d2.print();return 0;
}

我们给赋值运算符重载函数屏蔽调,看编译器是否会进行自动生成?

连续赋值呢?

所以默认生成的赋值运算符重载是可以实现连续对象赋值。

既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,但是和拷贝构造一样,并不是所有都是值拷贝,Date和Myqueue不需要我们自己实现赋值重载,因为Date是浅拷贝(值拷贝),Myqueue是自定义类型,但是Stack是需要自己去实现的,因为它是深拷贝,而默认生成的是浅拷贝.

🌈❌重载成全局函数

赋值运算符只能重载成类的成员函数不能重载成全局函数
就像命名空间域展开和全局变量一样的。
赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的
赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。
能不能声明和定义分离?——可以。类外面给定义,类里面给声明,还是成员函数。

你站在原地不动,就永远都是观众。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/136508.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android自定义 View惯性滚动效果(不使用Scroller)

效果图&#xff1a; 前言&#xff1a; 看了网上很多惯性滚动方案&#xff0c;都是通过Scroller 配合 computeScroll实现的&#xff0c;但在实际开发中可能有一些场景不合适&#xff0c;比如协调布局&#xff0c;内部子View有特别复杂的联动效果&#xff0c;需要通过偏移来配合…

使用Net2FTP轻松打造免费的Web文件管理器并公网远程访问

文章目录 1.前言2. Net2FTP网站搭建2.1. Net2FTP下载和安装2.2. Net2FTP网页测试 3. cpolar内网穿透3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 文件传输可以说是互联网最主要的应用之一&#xff0c;特别是智能设备的大面积使用&#xff0c;无论是个人…

“Python+高光谱遥感数据处理与机器学习教程

详情点击链接&#xff1a;“Python高光谱遥感数据处理与机器学习教程 第一&#xff1a;高光谱 一&#xff1a;高光谱遥感 01)高光谱遥感 02)光的波长 03)光谱分辨率 04)高光谱遥感的历史和发展 二&#xff1a;高光谱传感器与数据获取 01)高光谱遥感成像原理与传感器 02…

ubuntu 20.04 server安装

ubuntu 20.04 server安装 ubuntu-20.04.6-live-server-amd64.iso 安装 安装ubuntu20.04 TLS系统后&#xff0c;开机卡在“A start job is running for wait for network to be Configured”等待连接两分多钟。 cd /etc/systemd/system/network-online.target.wants/在[Servi…

Node Sass version 9.0.0 is incompatible with ^4.0.0.

1.错误产生原因&#xff1a; node、 node-sass 和sass-loader的版本对应问题 2.解决方案&#xff1a; 删除之前的 npm uninstall node-sass sass-loader 安装指定的 npm i node-sass4.14.1 sass-loader7.3.1 --save -dev

排序算法之-冒泡

顺序排序算法原理 从头开始遍历未排序数列&#xff0c;遍历时比较相邻的两个元素&#xff0c;前面的大于后面的&#xff0c;则双方交换位置&#xff0c;一直比较到末尾&#xff0c;这样最大的元素会出现在末尾&#xff0c;接着再依次从头开始遍历剩余未排序的元素&#xff0c;…

[架构之路-246]:目标系统 - 设计方法 - 软件工程 - 需求工程- 需求开发:获取、分析、定义、验证

目录 前言&#xff1a; 架构师为什么需要了解需求分析 一、需求工程概述 1.1 概述 1.2 需求工程的两大部分 &#xff08;1&#xff09;需求开发&#xff1a;系统工程师的职责、目标系统开发角度 &#xff08;2&#xff09;需求管理&#xff1a;项目管理者的职责、项目管…

微服务注册中心之安装+实例搭建zookeeper

1.下载安装包并上传到Linux服务器 Apache ZooKeeper 可以使用wget或者curl命令 wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz连接失败也可以本地下载之后上传到服务器 scp /本地/文件的/路径 用户名远程服务器IP或主…

CAN总线协议的理解以及移植stm32代码并使用

什么是CAN总线协议 是一种异步半双工的通讯协议&#xff0c;只有CAN_High与CAN_Low两条信号线。 有两种连接形式&#xff1a;闭环总线&#xff08;高速&#xff09;和开环总线&#xff08;远距离&#xff09; 他使用的是一种差分信号来传输电信号 所谓差分信号就是两条信号线…

接口--抽象方法

回答问题&#xff1a; 1.接口是什么&#xff1f; 2.接口中可以包含什么内容&#xff1f; 3.如何定义接口格式&#xff1f; 4.接口定义抽象方法格式&#xff1f; Code //接口是公共规范标准&#xff0c;类似于“模具” //如何定义接口格式&#xff1f;/** public interface 接…

CSS 对齐、组合选择符、伪类、伪元素、导航栏

一、CSS 对齐&#xff1a; 1&#xff09;、元素居中对齐&#xff1a; 水平居中对齐一个元素&#xff0c;可以使用margin&#xff1a;auto&#xff0c;设置到元素的宽度将防止它溢出到容器的边缘。元素通过指定宽度&#xff0c;并将两边的空外边距平均分配。示例&#xff1a; …

【前端】Jquery UI +PHP 实现表格拖动排序

目的&#xff1a;使用jquery ui库实现对表格拖拽排序&#xff0c;并且把排序保存到数据库中 效果如下 一、准备工作&#xff1a; 1、下载jquery ui库&#xff0c;可以直接引用线上路径 <link rel"stylesheet" href"https://code.jquery.com/ui/1.12.1/them…

IS-LM模型:从失衡到均衡的模拟

IS-LM模型&#xff1a;从失衡到均衡的模拟 文章目录 IS-LM模型&#xff1a;从失衡到均衡的模拟[toc] 1 I S − L M 1 IS-LM 1IS−LM模型2 数值模拟2.1 长期均衡解2.2 政府部门引入2.3 价格水平影响2.4 随机扰动因素 1 I S − L M 1 IS-LM 1IS−LM模型 I S − L M IS-LM IS−LM是…

如何在CPU上进行高效大语言模型推理

大语言模型&#xff08;LLMs&#xff09;已经在广泛的任务中展示出了令人瞩目的表现和巨大的发展潜力。然而&#xff0c;由于这些模型的参数量异常庞大&#xff0c;使得它们的部署变得相当具有挑战性&#xff0c;这不仅需要有足够大的内存空间&#xff0c;还需要有高速的内存传…

无需标注海量数据,目标检测新范式OVD

当前大火的多模态GPT-4在视觉能力上只具备目标识别的能力&#xff0c;还无法完成更高难度的目标检测任务。而识别出图像或视频中物体的类别、位置和大小信息&#xff0c;是现实生产中众多人工智能应用的关键&#xff0c;例如自动驾驶中的行人车辆识别、安防监控应用中的人脸锁定…

智慧工地源码 手册文档 app 数据大屏、硬件对接、萤石云

智慧工地解决方案依托计算机技术、物联网、云计算、大数据、人工智能、VR、AR等技术相结合&#xff0c;为工程项目管理提供先进技术手段&#xff0c;构建工地现场智能监控和控制体系&#xff0c;弥补传统方法在监管中的缺陷&#xff0c;最终实现项目对人、机、料、法、环的全方…

ZZ308 物联网应用与服务赛题第E套

2023年全国职业院校技能大赛 中职组 物联网应用与服务 任 务 书 &#xff08;E卷&#xff09; 赛位号&#xff1a;______________ 竞赛须知 一、注意事项 1.检查硬件设备、电脑设备是否正常。检查竞赛所需的各项设备、软件和竞赛材料等&#xff1b; 2.竞赛任务中所使用的…

文件包含漏洞培训

CTF介绍 MISC(Miscellaneous)类型,即安全杂项,题目或涉及流量分析、电子取证、人肉搜索、数据分析等等。CRYPTO(Cryptography)类型,即密码学,题目考察各种加解密技术,包括古典加密技术、现代加密技术甚至出题者自创加密技术。PWN类型,PWN在黑客俚语中代表着攻破、取得权限…

21 移动网络的前世今生

1、移动网络的发展历程 发展过程就是&#xff1a;2G,3G,4G,5G的过程&#xff0c;用2G看txt&#xff0c;用3G看jpg&#xff0c;用4G看avi。 2、2G网络 手机本来是用来打电话的&#xff0c;不是用来上网的&#xff0c;所以原来在2G时代&#xff0c;上网使用的不是IP网络&#…

关于视频封装格式和视频编码格式的简介

文章目录 简介视频封装格式&#xff08;Video Container Format&#xff09;视频编码格式&#xff08;Video Compression Format&#xff09;两者关系总结webm 格式简介webm视频编码格式webm音频编码格式webm总结 简介 视频封装格式&#xff08;Video Container Format&#x…