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

news2024/11/19 6:21:18

 

目录

一,日期类

二,运算符重载

 运算符重载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.coloradmin.cn/o/813383.html

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

相关文章

「BLIP 微调指南」以 Image-Text Captioning 任务为例

前言&#xff1a;近日需要用到 BLIP 微调下游任务&#xff0c;搜索发觉如今并无 BLIP 微调教程&#xff0c;下面就以 Image-Text Captioning 任务为例&#xff0c;演示如何完成 BLIP 模型在自己数据集上的微调。 目录 1. BLIP 介绍2. 关键代码定位3. 关键参数赋值4. 模型定义&a…

Scratch 教程 之 如何四舍五入保留一个小数到指定的数位

有些时候&#xff0c;我们需要四舍五入一个多位小数到指定的位&#xff0c;但scratch并没有这个积木&#xff0c;怎么做呢&#xff1f;我来教你&#xff5e; 我们创建一个函数&#xff0c;需要时调用就行了&#xff5e; 如图&#xff0c;创建一个带参函数&#xff0c;勾选"…

《GreenPlum系列-部署维护》GreenPlum数据库Standby故障处理

一、Standby故障 1.检查监控中心数据库状态 2.查看master节点数据库状态 su - gpadmin gpstate -f二、重启数据库 1.快速关闭数据库 [gpadminmdw pg_log]$ gpstop -M fast ... Continue with Greenplum instance shutdown Yy|Nn (defaultN): > y ...2.开启数据库 [gpad…

[SSM]Spring对事务的支持

目录 十六、Spring对事务的支持 16.1事务概述 16.2引入事务场景 16.3Spring对事务的支持 Spring实现事务的两种方式 Spring事务管理API 声明式事务之注解实现方式 事务属性 事务的全注解式开发 声明式事务之XML实现方式 十六、Spring对事务的支持 16.1事务概述 什么是…

stm32 mpu6050 cubemx DMP法读取角度

文章目录 前言一、相关文件二、cubemx配置三、代码变量初始化主循环 总结 前言 文件 记录使用dmp库来读取mpu6050的角度。 这是参考文件 参考1–主要参考 github参考 参考2 参考三 一、相关文件 相关文件在这里下载&#xff08;未填&#xff0c;不过可以在上面的git中下载&a…

(树) 剑指 Offer 28. 对称的二叉树 ——【Leetcode每日一题】

❓ 剑指 Offer 28. 对称的二叉树 难度&#xff1a;简单 请实现一个函数&#xff0c;用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样&#xff0c;那么它是对称的。 例如&#xff0c;二叉树 [1,2,2,3,4,4,3] 是对称的。 1/ \2 2/ \ / \3 4 4 3但是下面这个…

在Python中导入gurobipy模块显示ModuleNotFoundError: No module named ‘gurobipy‘的解决办法

笔者在学习用pythonAnacondagurobi求解优化问题时遇到了这个问题&#xff0c;看了很多帖子的方法都没有解决&#xff0c;所以这里分享一下自己的解决办法。 首先找到自己用的Anaconda3所在位置&#xff0c;这里不再赘述。 下拉文件夹找到envs&#xff0c;双击PythonProject&…

【雕爷学编程】MicroPython动手做(18)——掌控板之声光传感器

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

深入探索Linux文件系统与挂载点:掌握分区、挂载技巧

Linux 文件系统就是在 Linux 操作系统里咱们用来组织和管理文件的工具。它规定了文件和文件夹的结构&#xff0c;还确定了它们在存储设备上的储存方式。大致上来说&#xff0c;Linux 有很多种文件系统&#xff0c;比如 ext4、XFS、Btrfs 等。 挂载点其实就是把一个文件系统与 …

VS Code环境配置问题

VS Code 环境配置问题 文章目录 VS Code 环境配置问题配置 C问题解决不乱码只显示结果避免闪退&#xff0c;中文乱码 配置 Java下载 JDKJDK 环境配置安装插件 配置 C 跟着官网教程&#xff08;英文版&#xff09;和其他博客配置了一遍&#xff0c;却遇到了很多小问题&#xff…

2023“Java 基础 - 中级 - 高级”面试集结,已奉上我的膝盖

Java 基础&#xff08;对象线程字符接口变量异常方法&#xff09; 面向对象和面向过程的区别&#xff1f; Java 语言有哪些特点&#xff1f; 关于 JVM JDK 和 JRE 最详细通俗的解答 Oracle JDK 和 OpenJDK 的对比 Java 和 C的区别&#xff1f; 什么是 Java 程序的主类&…

Metabase 远程代码执行(CVE-2023-38646)

漏洞描述 Metabase是一款开源数据分析及可视化工具。它可允许用户连接至各种不同类型数据源,未经身份认证的攻击者可利用本漏洞在服务器上以运行 Metabase服务器的权限进行任意命令执行。 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩…

第133页的gtk+编程例子——计算器应用改写网上的例子用gtk4编译

第133页的gtk编程例子——计算器应用改写网上的例子用gtk4编译 来源&#xff1a;《GTK的计算器》 https://blog.csdn.net/zhouzhouzf/article/details/17097999 例子程序是在gtk2.0编译的&#xff0c;之前修改许多地方才能在gtk3.0编译通过&#xff0c;如今再修改能在gtk4编译…

进阶高级测试专项,Pytest自动化测试框架总结(三)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、pytest前置条件…

谈一谈缓存穿透,击穿,雪崩

缓存穿透 缓存穿透是指在使用缓存系统时&#xff0c;频繁查询一个不存在于缓存中的数据&#xff0c;导致这个查询每次都要通过缓存层去查询数据源&#xff0c;无法从缓存中获得结果。这种情况下&#xff0c;大量的请求会直接穿透缓存层&#xff0c;直接访问数据源&#xff0c;…

04 http连接处理(上)

基础知识&#xff1a;epoll、http报文格式、状态码和有限状态机 代码&#xff1a;对服务端处理http请求的全部流程进行简要介绍&#xff0c;然后结合代码对http类及请求接收进行详细分析。 epoll epoll_create函数 #include <sys/epoll.h> int epoll_create(int size)…

深度学习实践——模型部署优化实践

系列实验 深度学习实践——卷积神经网络实践&#xff1a;裂缝识别 深度学习实践——循环神经网络实践 深度学习实践——模型部署优化实践 深度学习实践——模型推理优化练习 源码&#xff1a; 1. 对应的github地址 https://github.com/Asionm/streamlit_demo 2. 对应的gitee地…

Session、Cookie 与 Application

目录 简介cookiecookie生命周期 sessionsession生命周期 application 简介 cookie、seesion、application三个都会缓存我们用户状态的数据&#xff0c;使得我们在浏览器访问网站时可以更快速的获取到信息。 主要原因在于HTTP协议是无状态的&#xff0c;我们每次访问服务器&…

软考05根据内存区域大小计算芯片数量

文章目录 前言一、原题二、解题思路1.计算内存区域的大小2.计算每个存储器芯片的容量3.计算芯片数量 总结 前言 从网上看题答案是有了&#xff0c;但是不知道具体的计算过程就很难受&#xff0c;不然下次还是不会&#xff0c;只能自己梳理了 一、原题 二、解题思路 1.计算内存…

ANR底层源码分析之Service篇

ANR底层源码分析之Service篇 一、前言二、Service-ANR原理2.1 Service启动ANR原理简述2.2 前台Service VS 后台Service的区别2.2.1 前台Service2.2.3 后台Service 2.3 Service启动ANR源码执行过程2.3.1 ActiveServices#bringUpServiceLocked2.3.2 ActiveServices#realStartServ…