Cpp学习——通过日期类来了解Cpp中的运算符重载

 

目录

一,日期类

二,运算符重载

 运算符重载1(比较)

1.< 

2. ==

复用

3.>

4.!=

5.<=

6.>=

运算符重载2(日期加减)

0.准备条件------计算每月的日期函数

1.+=

2.+

 3.-=

4.-

5.前置++

6.后置++

7前置--

6.后置--

7.计算两个日期的相差天数

  三,改进优化

四,源代码


一,日期类

写日期类的第一步是啥?当然是构建一个日期类啦。那这个类里面有啥啊?

1.成员变量:_year,_month,_day。

2.构造函数。

3.#include<iostream>。

4.using namespace std;

现在基本上就写这些。代码如下:

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:

	int _year;
	int _month;
	int _day;
};

 此时,我们的类对象就创建好了。我们便可以定义一个日期类对象了。在另一个cpp源文件里。

#include"Date.h"
int main()
{
	Date d1(2023, 8, 29);
	Date d2(2023, 8, 31);

}

 运行发现没有问题。

二,运算符重载

接下来我们来探索新功能吧。如果现在我们想要比较这两个日期的大小我们该如何比较呢?

答案是写个函数,但是纠结的点就来了:

1.不会英文,那就写个拼音来作函数名吧!但是如果你的同事是个老外怎么办?

2.会英文,那就起个英文名吧compare1,compare2,compare3,compare4。哈哈,这就难为死看的人了。

那到底要怎么办啊?直接用大于,小于号?但是这明显是不行的,因为类比较不了啊!此时一个叫做运算符重载的靓仔走过。

 运算符重载1(比较)

运算符重载是啥呢?运算符重载其实就是Cpp增加的一个新语法。通过一个叫做operator的关键字将一些符号重载,从而扩展该符号的功能。比如<号想要扩展功能的话便可以写成operator<函数。比如要比较上面的日期类,便可以写成如下代码:

1.< 

//思想:先比较年,再比较月,再比较天
bool Date:: operator<(const Date& d)
{
	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;
	}
	else
	{
		return false;
	}
}

 这样便实现了<的函数重载。当我们定义:Date d1(3023, 8, 29);       Date d2(2023, 8, 31);

时调用<比较时,编译器会把d1<d2解释为:d1.operator<(d2) 因为有this指针的原因再进一步剖析的话其实就是:operator<(&d1,d2)。

2. ==

在理解了上面的<运算符重载以后,便可以再趁热打铁写一个==运算符重载。代码如下:

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

等于便写出来了。

复用

其实在写完上面的两个运算符以后,其它的运算符便很好写了。比如大于,不就是!<嘛!

比如!=不就是!==嘛!比如大于等于不就是>或者==中的一个条件成立即可,小于等于不就是<和==中的一个条件成立即可。知道了这些以后,便可以着手写代码了:

3.>

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

4.!=

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

5.<=

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

6.>=

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

运算符重载2(日期加减)

在搞定了比较的运算符以后便可以来搞+,+=,-,-=,++,--;以及计算日期之间的差值的运算符重载了。

0.准备条件------计算每月的日期函数

其实在加减日期时最关键的便是计算出每个月的天数。日期天数计算代码如下:

int GetMonthDay(int year, int month)
{
	int MonthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//按平年写数组数据
	if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)))//如果是闰年便可以将二月的天数++
	{
		MonthDay[2]++;
	}
	return MonthDay[month];
}

1.+=

Date& Date:: operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}

2.+

+与+=的区别就是,+不改变自身,+=改变自身。所以复用+=实现+的运算符重载代码如下:

Date Date::operator+(int day)//此时的返回值就不能是Date&了,
                             //因为tmp是这个运算符重载函数里的临时变量。
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}

 补充说明:

为什么不先实现+而先实现+=呢?因为先实现+会比+=多几次拷贝。这样虽然不会对计算机的运行效率有太多的影响,但是为了发扬中国人民勤俭节约的美好品德还是先实现+=为好!

 3.-=

Date& Date:: operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

4.-

和前面的+一样,复用就完事了。

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

5.前置++

再实现前置++与后置++时可能大家会很好奇,这两个长得一摸一样的东西到底需要怎么区分呢?在这里可以这样区分:前置++是:operator ++(),后置++是:operator ++(int)。这个好像是祖师爷自己定义的,我们知道就可以了。所以代码如下:

Date& Date:: operator++()//因为前置++是先++后使用的所以直接改变*this
{
	*this += 1;
	return *this;
}

6.后置++

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

7前置--

前置--和后置--的声明也和前置++与后置++的声明类似,所以--的代码如下:

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

6.后置--

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

7.计算两个日期的相差天数

这个函数算是比较有意思的函数了,一开始我还不会写。但是在实现了前面的运算符重载以后这个函数代码的书写也就水到渠成了。具体代码如下:

int Date::operator-(Date& d)
{
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		max = d;
		min = *this;
	}

	int count = 0;
	while (min != max)
	{
		min+=1;
		count++;
	}
	return count;

}

  三,改进优化

大家能看出这里还有什么需要优化的地方吗?

1.判断日期是否合法,这该在那里判断呢?这是不是应该就要在传入日期的时候就判断啊?

所以判断日期是否合法就应该在构造函数里判断。

Date(int year, int month, int day)
	{
		if (day > GetMonthDay(year, month) || month >= 13)
		{
			cout << "日期非法" << endl;
		}
		_year = year;
		_month = month;
		_day = day;
	}

2.我们有没有可能想要计算一个日期+=负数的情况呢?以此来计算前面几天是什么日子呢?

答案是当然有,那我们该如何实现呢?还是复用。加等一个负数其实就是减等一个负的负数。减等一个负数其实就是+=一个负的负数。所以改进代码如下:

+=:

Date& Date:: operator+=(int day)
{
	if (day < 0)
	{
		*this -= (-day);
		return *this;
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_month++;
		_day -= GetMonthDay(_year, _month);
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}

-=:

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

	return *this;
}

3.打印日期,我们都知道自定义类型的变量都可以用cout打印出来。那我们是否可以将日期也用cout打印出来呢?答案是不能,那我们有没有办法打印出来呢?答案是有的,那就是运算符重载。代码如下:

​
ostream& operator<<(ostream& out, Date& d)
{
	out << d.Getyear() << "/" << d.Getmonth() << "/" << d.Getday() << endl;
	return out;
}

​

记得要将声明与定义分离!!!

四,源代码

1,Date.h

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
	{
		if (day > GetMonthDay(year, month) || month >= 13)
		{
			cout << "日期非法" << endl;
		}
		_year = year;
		_month = month;
		_day = day;
	}
	int GetMonthDay(int year, int month)
	{
		int MonthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//按平年写数组数据
		if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)))//如果是闰年便可以将二月的天数++
		{
			MonthDay[2]++;
		}
		return MonthDay[month];
	}

	int Getyear()
	{
		return _year;
	}

	int Getmonth()
	{
		return _month;
	}

	int Getday()
	{
		return _day;
	}

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

	Date&  operator+=(int day);
	Date operator+(int day);
	Date& operator-=(int day);
	Date operator-(int day);
	Date& operator++();
	Date operator++(int);
	Date& operator--();
	Date operator--(int);
	int operator-(Date& d1);
private:

	int _year;
	int _month;
	int _day;
};


ostream& operator<<(ostream& out,  Date& d);
istream& operator>>(istream& istream, Date& d);

2,Date.c:

#include"Date.h"
bool Date:: operator<(const Date& d)
{
	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;
	}
	else
	{
		return false;
	}
}


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

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

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

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

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


Date& Date:: operator+=(int day)
{
	if (day < 0)
	{
		*this -= (-day);
		return *this;
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_month++;
		_day -= GetMonthDay(_year, _month);
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}


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

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

	return *this;
}

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

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

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

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

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

int Date::operator-(Date& d)
{
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		max = d;
		min = *this;
	}

	int count = 0;
	while (min != max)
	{
		min+=1;
		count++;
	}
	return count;

}

ostream& operator<<(ostream& out, Date& d)
{
	out << d.Getyear() << "/" << d.Getmonth() << "/" << d.Getday() << endl;
	return out;
}

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

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

相关文章

接口自动化测试平台

下载了大神的EasyTest项目demo修改了下<https://testerhome.com/topics/12648 原地址>。也有看另一位大神的HttpRunnerManager<https://github.com/HttpRunner/HttpRunnerManager 原地址>&#xff0c;由于水平有限&#xff0c;感觉有点复杂~~~ 【整整200集】超超超…

多线程案例 | 单例模式、阻塞队列、定时器、线程池

多线程案例 1、案例一&#xff1a;线程安全的单例模式 单例模式 单例模式是设计模式的一种 什么是设计模式&#xff1f; 设计模式好比象棋中的 “棋谱”&#xff0c;红方当头炮&#xff0c;黑方马来跳&#xff0c;针对红方的一些走法&#xff0c;黑方应招的时候有一些固定的…

在OK3588板卡上部署模型实现OCR应用

一、主机模型转换 我们依旧采用FastDeploy来部署应用深度学习模型到OK3588板卡上 进入主机Ubuntu的虚拟环境 conda activate ok3588 安装rknn-toolkit2&#xff08;该工具不能在OK3588板卡上完成模型转换&#xff09; git clone https://github.com/rockchip-linux/rknn-to…

SpringBoot自动装配介绍

SpringBoot是对Spring的一种扩展&#xff0c;其中比较重要的扩展功能就是自动装配&#xff1a;通过注解对常用的配置做默认配置&#xff0c;简化xml配置内容。本文会对Spring的自动配置的原理和部分源码进行解析&#xff0c;本文主要参考了Spring的官方文档。 自动装配的组件 …

Golang安装

目录 Go安装下载安装Go Go安装 下载安装Go 地址&#xff1a;https://studygolang.com/dl 1、根据系统来选择下载包。 2、我是Window&#xff0c;所以直接下载windows的安装包来安装。 3、在控制台窗口输入“go version”可查看Go版本&#xff0c;检测是否安装成功。 4、配置…

【环境配置】使用Docker搭建LAMP环境

这篇文章不是介绍DOCKER是什么&#xff0c;也不是阐述DOCKER的核心&#xff1a;镜像/容器和仓库之间的关系,它只是一篇让刚刚接触DOCKER的初学者&#xff0c;在没有完全了解DOCKER是什么之前,也能尽快的在Linux系统下面通过DOCKER来搭建一个LAMP环境&#xff0c;这是其一&#…

Open3D(C++) 根据索引提取点云

目录 一、功能概述1、主要函数2、源码二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。爬虫网站自重,把自己当个人 一、功能概述 1、主要函数 std::shared_ptr<PointCloud> SelectByIn

IDEA安装热部署插件JRebel详解

JRebel 简介 JRebel是一套JavaEE开发工具。JRebel允许开发团队在有限的时间内完成更多的任务修正更多的问题&#xff0c;发布更高质量的软件产品。 JRebel是收费软件&#xff0c;用户可以在JRebel官方站点下载30天的评估版本。 Jrebel 可快速实现热部署&#xff0c;节省了大量重…

代码随想录算法训练营第二十五天 | 读PDF复习环节3

读PDF复习环节3 本博客的内容只是做一个大概的记录&#xff0c;整个PDF看下来&#xff0c;内容上是不如代码随想录网站上的文章全面的&#xff0c;并且PDF中有些地方的描述&#xff0c;是很让我疑惑的&#xff0c;在困扰我很久后&#xff0c;无意间发现&#xff0c;其网站上的讲…

前端html中让两个或者多个div在一行显示,用style给div加上css样式

文章目录 前言一、怎么让多个div在一行显示 前言 DIV是层叠样式表中的定位技术&#xff0c;全称DIVision&#xff0c;即为划分。有时可以称其为图层。DIV在编程中又叫做整除&#xff0c;即只得商的整数。 DIV元素是用来为HTML&#xff08;标准通用标记语言下的一个应用&#x…

图像处理之hough圆形检测

hough检测原理 点击图像处理之Hough变换检测直线查看 下面直接描述检测圆形的方法 基于Hough变换的圆形检测方法 对于一个半径为 r r r&#xff0c;圆心为 &#xff08; a , b &#xff09; &#xff08;a,b&#xff09; &#xff08;a,b&#xff09;的圆&#xff0c;我们将…

别再分库分表了,试试TiDB!

什么是NewSQL 传统SQL的问题 升级服务器硬件 数据分片 NoSQL 的问题 优点 缺点 NewSQL 特性 NewSQL 的主要特性 三种SQL的对比 TiDB怎么来的 TiDB社区版和企业版 TIDB核心特性 水平弹性扩展 分布式事务支持 金融级高可用 实时 HTAP 云原生的分布式数据库 高度兼…

M 芯片的 macos 系统安装虚拟机 centos7 网络配置

centos 安装之前把网络配置配好或者是把网线插好 第一步找到这个 第二步打开网络适配器 选择图中所指位置 设置好之后 开机启动 centos 第三步 开机以后 编写网卡文件保存 重启网卡就可以了&#xff0c;如果重启网卡不管用&#xff0c;则重启虚拟机即可 “ ifcfg-ens160 ” 这…

HTML快速学习

目录 一、网页元素属性 1.全局属性 2.标签 2.1其他标签 2.2表单标签 2.3图像标签 2.4列表标签 2.5表格标签 2.6文本标签 二、编码 1.字符的数字表示法 2.字符的实体表示法 三、实践一下 一、网页元素属性 1.全局属性 id属性是元素在网页内的唯一标识符。 class…

iOS开发-实现获取下载主题配置动态切换主题

iOS开发-实现获取下载主题配置动态切换主题 iOS开发-实现获取下载主题配置更切换主题&#xff0c;主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。 比如新年主题风格&#xff0c;常见的背景显示红色氛围图片、tabbar显示新…

【002 操作系统】进程的状态及状态转换图?

一、进程的状态 1. 创建状态 2. 就绪状态 3. 运行状态 4. 阻塞状态 5. 终止状态 图源&#xff1a;进程、线程基础知识全家桶&#xff0c;30 张图一套带走_Linux_小林coding_InfoQ写作社区 NULL -> 创建状态&#xff1a;一个新进程被创建时的第一个状态&#xff1b; 创建状态…

LT6911C 是一款HDMI 1.4到双端口MIPIDSI/CSI或者LVDS加音频的一款高性能芯片

LT6911C 1.描述&#xff1a; LT6911C是一款高性能的HDMI1.4到MIPIDSI/CSI/LVDS芯片&#xff0c;用于VR/智能手机/显示器应用程序。对于MIPIDSI/CSI输出&#xff0c;LT6911C具有可配置的单端口或双端口MIPIDSI/CSI&#xff0c;具有1个高速时钟通道和1个~4个高速数据通道&#…

nacos源码打包及相关配置

nacos 本地下载后&#xff0c;需要 install 下&#xff1a; mvn clean install -Dmaven.test.skiptrue -Dcheckstyle.skiptrue -Dpmd.skiptrue -Drat.skiptruenacos源码修改后&#xff0c;重新打包生成压缩包命令&#xff1a;在 distribution 目录中运行&#xff1a; mvn -Pr…

Java 源码打包 降低jar大小

这里写目录标题 Idea maven 插件配置pom.xml 配置启动技巧 Idea maven 插件配置 pom.xml 配置 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><!-- 只…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(11)-Fiddler设置安卓手机抓包,不会可是万万不行的!

1.简介 Fiddler不但能截获各种浏览器发出的 HTTP 请求&#xff0c;也可以截获各种智能手机发出的HTTP/ HTTPS 请求。 Fiddler能截获 Android 和 Windows Phone 等设备发出的 HTTP/HTTPS 请求。 今天宏哥讲解和分享Fiddler 如何截获安卓移动端发出的 HTTP/HTTPS 请求。 2.环…