运算符重载函数

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


函数名字为:关键字operator后面接需要重载的运算符符号。


函数原型:返回值类型 operator操作符(参数列表)


 

下面以日期类为例子

我们知道系统的基本类型可以进行,+、-等基本运算,但是用户的自定义类型,我们不能使用系统的基本类型+和-,需要对其进行函数名重载才能使用这些操作。

运算符既可以是成员函数,也可以是非成员函数。因为我们通常将用户自定义类型的数据定义为私有,在类外不能访问私有成员。所以通常,将运算符重载函数,定义为成员函数。特别注意,成员函数的形参列表,形参的个数比实际的个数少一个。因为有一个是这个类本身。

#pragma once

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cassert>
using namespace std;

class Date
{
public:

	Date(int year = 1, int month = 1, int day = 1)
	{
		if (month >= 13 || month <= 0
			|| day >= GetMonthDay(year, month) || day <= 0)
		{
			assert(false);
		}
		_year = year;
		_month = month;
		_day = day;
	}

	
	Date& operator=(const Date& d);

	bool operator<(const Date& d) const;
	bool operator==(const Date& d) const;
	bool operator<=(const Date& d) const;

	bool operator>=(const Date& d) const;
	bool operator>(const Date& d) const;
	bool operator!=(const Date& d) const;

	
	Date operator+(int day);

	Date& operator+=(int day);

	int GetMonthDay(int year, int month);

	Date& operator++();

	Date operator++(int);

	Date& operator-=(int day);

	Date operator-(int day);

	Date operator--(int);

	Date& operator--();

	int operator-(const Date& d);

	friend ostream& operator<<(ostream& out, const Date& d);

	friend istream& operator>>(istream& in, Date& d);






private:
	int _year;
	int _month;
	int _day;
};

=的运算符重载

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

	return *this;
}

等号运算符重载的返回值为Date& 类型,使用的是赋值后对象的自引用,可以减少拷贝,提高效率。如果this==&d,说明是自己对自己赋值,不需要进行操作。

==运算符重载

bool Date::operator==(const Date& d) const
{
	return _year == d._year && _month == d._month && _day == d._day;
}

==号运算符的重载判断年、月、日是否相等就可以了。

下面就是<、<=、>=、>等运算符的重载

<运算符的重载

bool Date::operator<(const Date& d) const
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year && _month < d._month)
	{
		return true;
	}
	else if (_year == d._year && _month == d._month && _day < d._day)
	{
		return true;
	}
	
	return false;
	
}

<=运算符的重载

在前面,我们已经实现过<、==的运算符重载。只需要复用前面的代码就可以实现<=的运算符重载。

bool Date::operator<=(const Date& d) const
{
	return (*this < d) || (*this == d);
}

>运算符的重载

>的反面就是<=,我们对<=取反就可以完成,>运算符的重载。

bool Date::operator>(const Date& d) const
{
	return !(*this <= d);
}

>=运算符的重载

>=的反面是<,只需要对<取反就可以完成>=的操作了。

bool Date::operator>=(const Date& d) const
{
	return !(*this < d);
}

!=运算符的重载

!=是==的反面

bool Date::operator>(const Date& d) const
{
	return !(*this <= d);
}

+=、+、-=、-运算符的重载

+=运算符的重载

int Date::GetMonthDay(int year,int month)
{
	int Arry[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
	{
		return Arry[month] + 1;
	}
	else
	{
		return Arry[month];
	}
}

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return (*this) -= -day;
	}
	else
	{
		_day += day;

		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			++_month;
			if (_month == 13)
			{
				_month = 1;
				++_year;
			}
		}

		return *this;
	}
	
}

如果一个类+=day,我们先将这个类的_day+day,再判断_day的天数,有没有大于这个月的天数,如果大于了,类的月份+1,月份+1后判断,月份是否超过了12,超过了的话将月份置为1,年份+1.循环往复,就可以就出+day后的日期了。

如果+=一个负数的天数,实际上是-=一个整数的天数,我们调用-=就好了。

+运算符的重载

+运算符和+=运算符类似。

比如: int a=3; 

a+3返回结果6,但是a还是3

a+=3,返回6,a变成了6

Date Date::operator+(int day)
{
	Date tmp = (*this);
	tmp += day;
	return tmp;
	
}

-=运算符的重载

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return (*this) += -day;
	}
	else
	{
		_day -= day;
		while (_day <= 0)
		{
			--_month;
			if (_month == 0)
			{
				_month = 12;
				--_year;

			}
			_day += GetMonthDay(_year, _month);
		}

		return *this;
	}
	
}

-=运算符的操作和+=的类似,我们先把类的_day-=day;如果得到一个负数,说明日期的_day不足以-day,我们需要向月份借天数,将月份--,然后_day+=借的那个月的天数。月份--之后,我们需要对月份判断是否正确,如果本来月份是1,--变成0,实际上是去年的12月,需要将_month=12,还有减少年份。之后就需要循环判断,直到_day>0为止。

-运算符的重载

-和-=运算符类似

Date Date::operator-(int day)
{
	Date tmp = (*this);
	tmp -= day;
	return tmp;
}

++、--运算符的重载

++运算符的重载

++分为前置++与后置++

前置++运算符的重载

前置++返回的是++后的结果

Date& Date::operator++()
{
	*this = *this + 1;

	return *this;
}

后置++的运算符重载

我们怎么区分前置和后置呢,在形参列表加入一个int就可以说明这个是后置++了。这个int便于编译器区分。

后置++返回的是++之前的结果,++的数据仍然就行了自增。

Date Date::operator++(int)
{
	Date tmp = (*this);
	*this =(*this)+1;

	return tmp;
}

前置--运算符重载函数

Date& Date::operator--()
{
	(*this) -= 1;
	return *this;
}

后置--运算符重载函数

Date Date::operator--(int)
{
	Date tmp = (*this);
	*this -= 1;
	return tmp;
}

那么我们如何计算两个日期相差多少天呢。利用日期-时期。所以需要我们构造日期-日期的运算符重载函数。

int Date::operator-(const Date& d)
{
	Date max=(*this);
	Date min=d;
	int flag = 1;

	if (*this < d)
	{
		max = d;
		min = (*this);
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		min++;
		n++;
	}

	return flag*n;
}

两个日期相减,我们需要先找到两个中较大的日期。

小的日期自增到与大的日期相等,自增的次数就是两个日期相差的天数。加一个flag标志用来区分日期相差的正负。

<<流插入运算符重载。我们知道流插入运算符可以打印基本数据类型。用户自定义的类型,能不能使用系统自带的流插入运算符呢?是不行的,需要我们进行函数名重载,便于支持自定义类型的打印。

ostream& operator<<(ostream& out,const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;

	return out;
}

流插入运算符的重载函数。不能作为类的成员函数,因为成员函数的第一个参数默认是类的this指针。但是我们使用流插入运算符是cout<<d<<endl;第一个参数为cout,所以我们不能使用成员函数作为重载函数,那么我们类外不能访问私有成员。该怎么办?我们将函数声明为友元函数,友元函数可以在类外访问私有成员。

在类内加入

为什么返回类型为ostream呢,因为这样可以做到连续的流插入,输出多个结果。

流提取运算符重载函数

我们知道>>可以输入基本的数据类型。但是日期类是我们自定义的类型。我们使用>>输入就需要对>>进行运算符重载。

与流插入运算符的重载函数一样。流提取运算符重载函数,也不能使用成员函数。写在类外将这个函数作为类的友元函数。

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;

	return in;
}

在类内声明:

对<<、>>进行了运算符重载。我们就可以直接使用其操作了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习-决策树

1、什么是决策树&#xff1f; 一种描述概念空间的有效的归纳推理办法。基于决策树的学习方法可以进行不相关的多概念学习&#xff0c;具有简单快捷的优势&#xff0c;已经在各个领域取得广泛应用。 决策树是一种树型结构&#xff0c;其中每个内部结点表示在一个属性上的测试&a…

大数据Doris(五十六):SQL函数之地理位置函数

文章目录 SQL函数之地理位置函数 一、​​​​​​​ST_AsText(GEOMETRY geo)

Java - Lombok的添加和使用详解

目录 &#x1f436;6.1 lombok介绍 &#x1f436;6.2 lombok使用 1. &#x1f959;添加方法一 2. &#x1f959;添加方法2 3. 使用 &#x1f436;6.3 lombok常用注解 1. &#x1f959;Getter和Setter 2. &#x1f959;ToString 3. &#x1f959;NoArgsConstructor和Al…

Docker入门安装、镜像与容器下载 —— 基本操作

目录 前言 Docker 1. docker介绍 2. docker安装 3. docker基本使用 3.1 镜像下载 3.2 操作容器 前言 虚拟机&#xff1a;基于主机(物理机或虚机)的多服务实例。在该模式下&#xff0c;软件开发人员可以提供单个或多个物理机或虚机&#xff0c;同时在每个主机上运行多个服…

【务实笔记】总要朝前看

最近关注了鱼皮的编程导航&#xff0c;打算跟着鱼皮做一做项目&#xff0c;为研究生复试作准备。其实我原先已经有一个C高并发服务器的项目了&#xff0c;只不过最近很无奈&#xff0c;开始打造前端页面的时候&#xff0c;虚拟机Qt安装界面死活卡在了第一步&#xff1a; ┭┮﹏…

Java多线程并发篇----第十七篇

系列文章目录 文章目录 系列文章目录前言一、为什么要用 join()方法?二、线程唤醒(notify)三、线程其他方法四、进程五、上下文前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享…

用Python实现USB插拔测试

测试目的 我司的产品需要进行唤与睡眠状态之间的切换测试&#xff0c;而且需要进行长时间的压力测试。由于没有插拔USB的机械设备&#xff0c;所以我这边就需要设计一个能模拟USB插拔的测试环境。 设计 测试环境的设计只能根据现有资源来进行&#xff0c;所以我这边给出的方…

Html+Css+JavaScript实现完整的轮播图功能

概要 这个案例具备常见轮播图完整的功能&#xff0c;大家可以根据自己的需求去修改&#xff1b; 代码可以直接复制运行&#xff0c;需要安装sass 主要功能&#xff1a; &#xff08;1&#xff09;鼠标移入轮播图&#xff0c;左右两边的按钮出现&#xff0c;离开则隐藏按钮&a…

【前后端的那些事】开源!treeSelect树形结构数据展示

文章目录 tree-selector1. 新增表单组件2. 在父组件中引用3. 父组件添加新增按钮4. 树形组件4.1 前端代码4.2 后端代码 前言&#xff1a;最近写项目&#xff0c;发现了一些很有意思的功能&#xff0c;想写文章&#xff0c;录视频把这些内容记录下。但这些功能太零碎&#xff0c…

qemu、virt-manager克隆虚拟机

前提 必须先关闭虚拟机&#xff0c;不然克隆按钮是灰的&#xff0c;不能点击 克隆虚拟机 选择虚拟机--克隆 点击克隆 等待完成克隆 下图说明已经克隆成功 运行虚拟机

IntelliJ IDEA安装来了

IDEA 全称 IntelliJ IDEA&#xff0c;是java编程语言的集成开发环境。IntelliJ在业界被公认为最好的Java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超…

接口interface--java学习笔记

认识接口 java提供了一个关键字interface&#xff0c;用这个关键字可以定义出一个特殊的结构&#xff1a;接口在接口里面定义的变量&#xff0c;不管加不加public static final修饰都默认为常量&#xff0c;必须赋初值在接口里面定义的方法&#xff0c;不管加不加public abstr…

Java 10_000 代表什么意思? 数字里面混夹着下划线?

先放一张图 &#xff0c;这到底是sleep了多久&#xff1f; public static void main(String[] args) {int a 10_000; System.out.println(a); // 10000} java 7 的 特性 &#xff1a;https://docs.oracle.com/javase/7/docs/technotes/guides/language/underscores-literals…

SCSI/UFS储存 基础

一、UFS协议 UniPro 的上面就是 UTP 和 SCSI 命令集&#xff0c;由于涉及的 SCSI 命令是很大一块需要单独来讲&#xff0c;所以这里只简单两笔。正如最开始提到的&#xff0c;UTP 和 SCSI 是属于 SCSI 这部分&#xff0c;在 JEDEC 的标准里能找到它们的具体说明。 UTP&#xf…

第一篇:node的背景及版本的检查

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 前言 Node.js 是一个基于 Chrome V8 JavaScript 引擎…

如何使用Docker一键部署WBO白板并实现固定公网地址远程访问

文章目录 前言1. 部署WBO白板2. 本地访问WBO白板3. Linux 安装cpolar4. 配置WBO公网访问地址5. 公网远程访问WBO白板6. 固定WBO白板公网地址 前言 WBO在线协作白板是一个自由和开源的在线协作白板&#xff0c;允许多个用户同时在一个虚拟的大型白板上画图。该白板对所有线上用…

机器学习算法实战案例:VMD-LSTM实现单变量多步光伏预测

文章目录 机器学习算法实战案例系列答疑&技术交流1 数据处理1.1 导入库文件1.2 导入数据集1.3 缺失值分析 2 VMD经验模态分解3 构造训练数据4 LSTM模型训练5 预测 机器学习算法实战案例系列 机器学习算法实战案例&#xff1a;确实可以封神了&#xff0c;时间序列预测算法最…

《MyBatis》-- 流式查询内存性能优化-单条数据加工

阿丹-需求/场景&#xff1a; 在项目场景中涉及到数据二次加工。需要将单个对象数据转为按照规定的数据字典的转换。以及需要转换数据结构。从对象转换为按照规定的值和规则的数组。 因为要写入csv文件&#xff0c;涉及到文件的输出流。 之前讨论针对的解决方案&#xff1a; …

统计学R语言 实验3 点估计

统计学R语言 实验3 点估计 一、实验目的 1. 掌握理解点估计的相关概念和方法。 2. 掌握理解点估计的估计质量好坏判断方法。 3. 熟悉R语言等语言的集成开发环境。 二、实验分析与内容 某灯泡厂从某日生产的一批灯泡中抽取10个灯泡进行寿命试验&#xff0c;得到灯泡寿命&…

鸿蒙开发笔记(七):应用状态管理,LocalStorage及AppStorage的使用

开发者要实现应用级的&#xff0c;或者多个页面的状态数据共享&#xff0c;就需要用到应用级别的状态管理的概念。ArkTS根据不同特性&#xff0c;提供了多种应用状态管理的能力&#xff1a; LocalStorage&#xff1a;页面级UI状态存储&#xff0c;通常用于UIAbility内、页面间的…