详解运算符重载,赋值运算符重载,++运算符重载

news2025/1/17 3:57:56

目录

前言

运算符重载

概念

目的

写法

调用

注意事项

详解注意事项

运算符重载成全局性的弊端

类中隐含的this指针

赋值运算符重载

赋值运算符重载格式

注意点

明晰赋值运算符重载函数的调用

连续赋值

传引用与传值返回

默认赋值运算符重载

前置++和后置++重载


前言

先梳理一下本篇的脉络,首先会讲解运算符重载的概念,这是本篇的基本概念。其次会讲解赋值运算符的重载,这是本篇的重点,最后是++运算符重载,只需明晰规则即可。此外,希望这篇文章能让大家有所收获


运算符重载

概念

C++引入了运算符重载。它和函数重载的概念类似,可以让一个符号有不同的功能而具体的功能是由自己实现的。

目的

是为了增强代码的可读性。因为C++中有这个概念,“  + ” 这个符号可以实现两个整形或浮点型相加,因为这两个类型是语言自己定义的。但它能实现两个的相加吗?显然不行,因为这个类型是自己设计的,相加要实现怎样的效果只有自己知道。

写法

运算符重载也是函数的一种,只不过函数名比较特殊其返回值和参数列表和普通函数一样。参数的数量和操作数的数量一致,参数的顺序和操作数的顺序一致

函数名字为:关键字 operator 后面接需要重载的运算符符号
函数原型: 返回值类型 operator操作符(参数列表)
示例(判断两个日期类是否相等)

调用

分为显式调用(加关键字)和隐式调用(不加关键字),如下代码

operator==(d1, d2)//显式调用
==(d1, d2) //隐式调用

注意事项

运算符重载的注意事项
1.
不能通过连接其他符号来创建新的操作符:比如operator@
2.
重载操作符必须有一个类类型参数
3.
用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
4.
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
5.
.*   ::   sizeof   ?:   . 注意以上5个运算符不能重载。
详解注意事项

1.想要重载一个符号,必须复用语言定义过的符号,不能凭空捏造。如下代码就会报错。


bool operator@(const Date& d1, const Date& d2)

2.假如要把“  ”这个符号重载成整形和字符型的相加,这毫无意义并且会破坏语言原有的运算规则,此时编译器会强制报错。

3.如果要把加“  ”这个符号重载两个相加,那具体实现的逻辑就必须是加的逻辑,但这一点没有强制性,因为这不是语法的错误,编译器不会强行报错。需要自行规范。

4.这一点会在下面提到。

5. .*   ::   sizeof   ?:   .  这五个运算符强制不能重载,大家可能对于 .* 运算符比较陌生, .* 运算符并不是本篇章的重点,但为了大家能够记住这个运算符,小编写了一段代码并且配上了详细的注释让大家感受一下 .* 运算符的作用。提醒:对 .* 运算符不感兴趣的可以跳过,不会对后面内容的理解有任何影响

class Date //日期类
{
public:
	Date(int year = 1, int month = 1, int day = 1) //构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void DatePrintf() //打印函数
	{
		cout << _year << _month << _day << endl;
	}

private:

	int _year; //年
	int _month; //月
	int _day; //日

};

typedef void(Date::* DP)();  //这里是给一个函数类型取了一个别名,别名是 DP ,类型是 void ()  日期类中的打印函数也是这个类型

int main()
{
	DP dp = &Date::DatePrintf; //把成员函数中打印函数的指针给  dp , 一般来说函数名就代表该函数的地址,但成员函数规定要加上取地址符号

	Date d; //实例化一个类 , 对象名为d

	(d .* dp)();  //调用d对象的打印函数

	return 0;
}

上述代码中提到了构造函数,小编专门写了一篇构造函数的文章  http://t.csdnimg.cn/vGE9A 对构造函数不是很理解的可以看一下,上述代码运行的结果是打印三个一,如下图:

运算符重载成全局性的弊端

的数据一般是私有的,运算符重载是函数的一种,而全局性的函数是不可以访问类的私有数据的。如下图:

难道我们要为了运算符重载要把中的数据设为共有吗,那的封装性如何保证呢?本片给出的解决方案是把运算符重载函数定义为成员函数,意思是直接定义在类中。如下代码

class Date //日期类
{
public:
	Date(int year = 1, int month = 1, int day = 1) //构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

	bool operator==(const Date& d2)  //运算符重载函数,一个参数是this ,一个是 const Date&
	{
		return _year == d2._year

			&& _month == d2._month 

			&& _day == d2._day;
	}
private:

	int _year; //年
	int _month; //月
	int _day; //日

};

中隐含的this指针

如果把运算符重载函数定义成员函数会少定义一个参数,但并没有真的少了一个参数,有一个隐含的this指针作为了该函数的第一个参数。如下图:

this是类型的隐含参数,如果运算符重载函数定义再了里面,这个参数就可以省去不写。



赋值运算符重载

下面的内容涉及到拷贝构造函数,对拷贝构造函数的理解比较模糊的可以参考一下小编写的详解拷贝构造一文   http://t.csdnimg.cn/CkLs5  。

赋值运算符重载格式

参数类型:类类型的引用

返回值:可传值返回,可传引用返回,传引用返回比传值返回效率要高,后面会细讲。

代码示例

Date& operator=(const Date& d) //日期类的赋值运算符的重载的定义
 {
            _year = d._year;
            _month = d._month;
            _day = d._day;
       }


在这里先定义一个日期类,下面讨论的知识点都会用到这个日期类,大家先看一下代码

class Date  //日期类
{
public:
	Date(int year = 1, int month = 1, int day = 1)  //全缺省构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

	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 d; //实例化d

	Date d1(d);  //示例化d1,并把d的值拷贝给d1

	Date d2 = d;  //示例化d2,并把d的值拷贝给d2

	Date d3;  //实例化d3

	d3 = d;  //把d的值赋值给d3


}

画图演示其调用

连续赋值

上述代码中的赋值重载函数随是否能实现连续赋值呢?答案是不能。因为该函数只能完成赋值工作,并不会再把类的数据返回。代码改进

Date operator=(const Date& d)  //赋值运算符重载
{

		_year = d._year;
		_month = d._month;
		_day = d._day;
	
	return *this;  //返回被赋值的形参的数据
}

传引用与传值返回

上述代码中传的是的值,由于中封装了许多数据,想要把的数据传回去,需要调用该的拷贝构造函数,我们可以打印一下拷贝构造函数来观察一下,如下图

调用拷贝构造函数拷贝数据的消耗是很大的,如果传引用返回能不能减少拷贝呢,如下图

结果很明确,传引用返回并没有调用拷贝构造函数,这说明传引用返回比传值返回效率更高,只要该类出了作用域不会销毁,都可以传引用返回

如果我要自己给自己赋值会怎么样呢,这是没必要的,可以再改进一下代码

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

	return *this;
}

默认赋值运算符重载

用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝 。内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
我将用如下代码为大家讲解默认运算符重载函数的浅拷贝的弊端
class Date //日期类
{
public:

	Date() //构造函数
	{
		_year = 1;
		_month = 1;
		_day = 1;

		_a = (int*)malloc(sizeof(int) * 7); //为a开辟空间
		for (int i = 0; i < 7; i++)
		{
			_a[i] = 0;
		}
	}


private:
	int _year; //年
	int _month; //月
	int _day;  //日
	int* _a;  //指向一块空间
};
int main()
{
	Date d; //实例化对象d
	Date d1; //实例化对象d1

	d = d1; //把对象d1的数据赋值给对象d
}

下面是代码调试示意图

下面是逻辑示意图
对象d的_a不再指向原有空间,使原有空间丢失,造成内存泄漏。 如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必 须要实现


前置++和后置++重载

Date& operator++() //日期的前置++
{
	_day += 1;
	return *this;
}

	Date operator++(int) //日期类的后置++
{
	Date temp(*this);
	_day += 1;
	return temp;
}
 C++规定:  前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载,后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递。


想为大家推荐 aMereNobody 大佬写的文章   http://t.csdnimg.cn/m9uVE 

本篇的内容到此结束啦

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

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

相关文章

使用 Flask-WTF 防止跨站请求攻击(CSRF):一份全面指南

在构建 Web 应用时&#xff0c;防止跨站请求攻击&#xff08;CSRF&#xff09;是一项至关重要的安全措施。CSRF 攻击允许恶意网站执行未经授权的操作&#xff0c;如用户身份验证或数据篡改。幸运的是&#xff0c;Flask-WTF 库为我们提供了强大的 CSRF 保护功能。在本篇博客中&a…

【模拟】Leetcode 数青蛙

题目讲解 1419. 数青蛙 算法讲解 class Solution { public:int minNumberOfFrogs(string croakOfFrogs) {string target "croak";int n target.size();//保存target每个字符的位置indexunordered_map<char, int>index;for(int i 0; i < n; i)index[tar…

Day08React——第八天

useEffect 概念&#xff1a;useEffect 是一个 React Hook 函数&#xff0c;用于在React组件中创建不是由事件引起而是由渲染本身引起的操作&#xff0c;比如发送AJAx请求&#xff0c;更改daom等等 需求&#xff1a;在组件渲染完毕后&#xff0c;立刻从服务器获取频道列表数据…

什么是Rust语言?探索安全系统编程的未来

&#x1f680; 什么是Rust语言&#xff1f;探索安全系统编程的未来 文章目录 &#x1f680; 什么是Rust语言&#xff1f;探索安全系统编程的未来摘要引言正文&#x1f4d8; Rust语言简介&#x1f31f; 发展历程&#x1f3af; Rust的技术意义和优势&#x1f4e6; Rust解决的问题…

HarmonyOS开发实例:【分布式新闻客户端】

介绍 本篇Codelab基于栅格布局、设备管理和多端协同&#xff0c;实现一次开发&#xff0c;多端部署的分布式新闻客户端页面。主要包含以下功能&#xff1a; 展示新闻列表以及左右滑动切换新闻Tab。点击新闻展示新闻详情页。点击新闻详情页底部的分享按钮&#xff0c;发现周边…

Go 之 sync.Mutex 加锁失效现象

我先声明一下&#xff0c;并不是真的加锁失效&#xff0c;而是我之前的理解有误&#xff0c;导致看起来像是加锁失效一样。于是乎记录一下&#xff0c;加深一下印象。 我之前有个理解误区&#xff08;不知道大家有没有&#xff0c;有的话赶紧纠正一下——其实也是因为我这块的…

项目7-音乐播放器5+注册账号

1.前端代码 MAPPER Insert("insert into user(username,password) values (#{username},#{password}) ")Integer insertUserInfo(String username,String password); Service public Result insertUserInfo(String username, String oldpassword,String newpasswo…

算法学习——LeetCode力扣补充篇11(64. 最小路径和、48. 旋转图像 、169. 多数元素、394. 字符串解码、240. 搜索二维矩阵 II )

算法学习——LeetCode力扣补充篇11 64. 最小路径和 64. 最小路径和 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;每次只…

测绘管理与法律法规 | 测绘资质管理办法 | 学习笔记

目录 一、测绘资质概述 二、测绘资质分类与等级 三、审批与管理 四、申请条件 五、审批程序 六、测绘资质证书 七、监督管理 八、违规处理 九、特殊规定 十、审批受理时间要点补充 1. 审批机关决定是否受理的时间 2. 审批机关作出批准与否的决定时间 3. 颁发测绘资…

在报表控件 FastReport .NET 中使用 PageCreate 事件

FastReport Business Graphics .NET&#xff0c;是一款基于fastreport报表开发控件的商业图形库&#xff0c;借助 FastReport 商业图形库&#xff0c;您可以可视化不同的分层数据&#xff0c;构建业务图表以进行进一步分析和决策。利用数据呈现领域专家针对 .NET 7、.NET Core、…

论文阅读-Federated-Unlearning-With-Momentum-Degradation

论文阅读-Federated Unlearning With Momentum Degradation 联邦忘却与动量退化 Yian Zhao IEEE Internet of Things Journal 2023 年 10 月 2 日 CCF-C momentum degradation-MoDe 动量退化 memory guidance-记忆引导 knowledge erasure-知识擦除 Deep-learning neural n…

【记录】Python|Selenium 下载 PDF 不预览不弹窗(2024年)

版本&#xff1a; Chrome 124Python 12Selenium 4.19.0 版本与我有差异不要紧&#xff0c;只要别差异太大比如 Chrome 用 57 之前的版本了&#xff0c;就可以看本文。 如果你从前完全没使用过、没安装过Selenium&#xff0c;可以参考这篇博客《【记录】Python3&#xff5c;Sele…

搭建Zookeeper完全分布式集群(CentOS 9 )

ZooKeeper是一个开源的分布式协调服务&#xff0c;它为分布式应用提供了高效且可靠的分布式协调服务&#xff0c;并且是分布式应用保证数据一致性的解决方案。该项目由雅虎公司创建&#xff0c;是Google Chubby的开源实现。 分布式应用可以基于ZooKeeper实现诸如数据发布/订阅…

UE5 C++ 射线检测

一.声明四个变量 FVector StartLocation;FVector ForwardVector;FVector EndLocation;FHitResult HitResult;二.起点从摄像机&#xff0c;重点为摄像机前9999m。射线检测 使用LineTraceSingleByChannel 射线直线通道检测&#xff0c;所以 void AMyCharacter::Tick(float Delt…

c++ qt6.5 打包sqlite组件无法使用,尽然 也需要dll支持!这和开发php 有什么区别!

运行 程序会默认使用当前所在文件夹中的 dll 文件&#xff0c;若文件不存在&#xff0c;会使用系统环境变量路径中的文件&#xff1b;又或者是需要在程序源代码中明确指定使用的 dll 的路径。由于我安装 Qt 时将相关 dll 文件路径都添加到了系统环境变量中&#xff0c;所以即使…

Hbase的shell命令(详细)

一、help 1.help 显示命名的分组情况 2.help 命令名称 查看命令的具体使用&#xff0c;包括命令的作用和用法。 举例&#xff1a;help list 二、general 组&#xff08;普通命令组&#xff09; 命令 描述 …

设计循环队列(队列oj)

1.设计循环队列 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#xff08;先进先出&#xff09;原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的空间。…

高版本Android studio 使用Markdown无法预览(已解决)

目录 概述 解决方法 概述 本人升级Android studio 当前版本为Android Studio Jellyfish | 2023.3.1 RC 2导致Markdown无法预览。 我尝试了很多网上的方法都无法Markdown解决预览问题&#xff0c;包括升级插件、安装各种和Markdown相关的插件及使用“Choose Boot Java Runtim…

CentOS系统上部署Docker,mysql,nginx

CentOS7系统上部署Docker&#xff0c;mysql&#xff0c;nginx 未完&#xff0c;持续更新中 更新软件包索引&#xff1a; 首先&#xff0c;确保你的CentOS系统是最新的。你可以通过运行以下命令来更新你的系统&#xff1a; yum update安装Docker&#xff1a; CentOS的软件仓…

十大开源机器人 智能体

1- Poppy 网址 https://www.poppy-project.org/en/ 2- Nao 网址:https://www.aldebaran.com/en/nao 3- iCub 网址: https://icub.iit.it/