C++日期类详解 第二级支线任务

news2024/9/20 22:51:31

日期类的整体

class Date
{
public:
	// 构造函数
	Date(int year = 0, int month = 1, int day = 1);
	// 打印函数
	void Print() const;
	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day) const;
	// 日期-=天数
	Date& operator-=(int day);
	// 日期-天数
	Date operator-(int day) const;
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 前置--
	Date& operator--();
	// 后置--
	Date operator--(int);
	// 日期的大小关系比较
	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;
	// 日期-日期
	int operator-(const Date& d) const;

	// 析构,拷贝构造,赋值重载可以不写,使用默认生成的即可

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

上述代码表示了这次要实现的类,包括了多种运算符的重载,以及构造函数,相似的操作符,我们只实现一个。

日期类的析构和拷贝赋值函数不用写用默认的,因为日期类用的都是内置类型,没有动态开辟的空间,所以不用考虑深拷贝的问题

构造函数

// 获取某年某月的天数
inline int getmonthday(int year, int month)
{
	// 数组存储平年每个月的天数
	static int dayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	int day = dayArray[month];
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		//闰年2月的天数
		day = 29;
	}
	return day;
}
// 构造函数
Date::Date(int year, int month, int day)
{
	// 检查日期的合法性
	if (year >= 0
	&& month >= 1 && month <= 12
	&& day >= 1 && day <= getmonthday(year, month))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		// 严格来说抛异常更好
		cout << "非法日期" << endl;
		cout << year << "年" << month << "月" << day << "日" << endl;
        exit(1);
	}
}

上述代码解析:

一.getmonthday:这个函数用来判断是哪一年的哪一个月有几天

细节:

1.用static或者全局变量开辟dayArray[13],好处在于:节省每次调用函数时重复制造dayArray[13]。

2.inline内联函数,因为在Date对象进行++ -- 还有构造函数等多个函数都要用到getmonthday,所以用内联在调用的地方直接展开,省去了调用函数时找地址的时间消耗。

二.构造函数:构造函数很简单,但对于日期而言,每个月没有32天,没有13月,所以在构造函数要对传入的参数进行审批。错了以后直接exit退出。


operator+=和operator-=

为什么二者要一起讲,因为可以二者可以复用。

+=

// 日期+=天数
Date& Date::operator+=(int day)
{
	if (day<0)
	{
		// 复用operator-=
		*this -= -day;
	}
	else
	{
		_day += day;
		// 日期不合法,通过不断调整,直到最后日期合法为止
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month > 12)
			{
				_year++;
				_month = 1;
			}
		}
	}
	return *this;
}

对于上述代码:为什么负数时我们复用-=,因为负数时,我们的日期是减法,但是在加等的逻辑中我们只考虑通过加法去改变日期,所以只考虑日期超限制的情况,如果减法倒退超过限制,我们不用单独写逻辑,而是直接复用-=的逻辑即可。

-= 

// 日期-=天数
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		// 复用operator+=
		*this += -day;
	}
	else
	{
		_day -= day;
		// 日期不合法,通过不断调整,直到最后日期合法为止
		while (_day <= 0)
		{
			_month--;
			if (_month == 0)
			{
				_year--;
				_month = 12;
			}
			_day += GetMonthDay(_year, _month);
		}
	}
	return *this;
}

 对于上述代码:和+= 相同,-=只考虑下限不考虑上限。所以负数时复用+=。

 记住:减法考虑下限,加法考虑上限,负数考虑复用

operator+

// 日期+天数
Date Date::operator+(int day) const
{
	Date tmp(*this);// 拷贝构造tmp,用于返回
	// 复用operator+=
	tmp += day;

	return tmp;
}

对于上述代码:

1.我们复用了+= 。

2.为什么要用拷贝构造:参考int 时的加法;如果只是单纯的+1那对i并不影响,而如果是将i + 1赋值给i 那才会对 i 造成影响。所以拷贝构造出一份新的对象,返回这个新对象。而不是在原对象上更改

int i = 0;
i+1;
i = i + 1;

operator- 和 + 同理。 

前置++和后置++

和内置类型一样,前置++返回的是修改后的内容,后置++修改值,但是返回的是没++的内容。

前置++

// 前置++
Date& Date::operator++()
{
	// 复用operator+=
	*this += 1;
	return *this;
}

可以看到我们之间返回了*this,并且直接更改的*this。 

后置++

// 后置++
Date Date::operator++(int)
{
	Date tmp(*this);// 拷贝构造tmp,用于返回
	// 复用operator+=
	*this += 1;
	return tmp;
}

后置++因为我们要返回的值是修改前的,所以我们拷贝构造后返回tmp,但不能引用!!!局部变量后续会销毁,但是传值传出去的是复制体,所以要用传值返回

前置--和后置--同理。

比较运算符

operator==

这里以==为例,其他的符号只是逻辑不同但是代码是类似的。

但值得一提的有:>= 可以复用 operator> 和 operator==. <= 同理。

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

把该判断的都判断了就对了。

日期-日期

日期类的计算难点就在于,日期的进位,但是对于日期相减是有一个取巧的方法滴。

日期-日期,算天数,我们可以找到较大的日期,然后用较小的日期一直+1,直到 == 较大的日期。中间在用一个变量一直计算+了多少个1.就可以实现了。

// 日期-日期
int Date::operator-(const Date& d) const
{
	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 n*flag;
}

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

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

相关文章

常用的k8s容器网络模式有哪些?

常用的k8s容器网络模式包括Bridge模式、Host模式、Overlay模式、Flannel模式、CNI&#xff08;ContainerNetworkInterface&#xff09;模式。K8s的容器网络模式多种多样&#xff0c;每种模式都有其特点和适用场景。Bridge模式适用于简单的容器通信场景&#xff1b;Host模式适用…

将阮一峰老师的《ES6入门教程》的源码拷贝本地运行和发布

你好同学&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注。 阮一峰老师的《ES6入门教程》应该是很多同学学习 ES6 知识的重要参考吧&#xff0c;应该也有很多同学在看该文档的时候&#xff0c;想知道这个教程的前端源码是怎么实现的&#xff0c;也可能有同学下载…

掌握Python-uinput:打造你的输入设备控制大师

文章目录 掌握Python-uinput&#xff1a;打造你的输入设备控制大师背景&#xff1a;为何Python-uinput不可或缺&#xff1f;Python-uinput是什么&#xff1f;如何安装Python-uinput&#xff1f;简单库函数使用方法创建虚拟设备模拟按键模拟鼠标移动模拟滚轮滚动关闭设备 场景应…

IP Source Guard技术原理与应用

目录 IP Source Guard概述 IP Source Guard源数据表项 IP Source Guard源数据-静态添加 IP Source Guard查看 IP Source Guard使用注意事项 IP Source Guard概述 局域网IP冲突给网络的运维带来很大困扰存在以下风险&#xff1a; 使用手工配置IP地址的方式上网&#xff0c…

Redis——C++库redisplusplus在Linux环境下的安装

目录 第一步&#xff0c;安装hiredis第二步&#xff0c;下载redis源码第三步&#xff0c;编译/安装 redis-plus-plus使用redis-plus-plus(以Centos为例)Ubuntu的Makefile 第一步&#xff0c;安装hiredis redis-plus-plus 是基于 hiredis 实现的&#xff0c;而hiredis 是⼀个 C…

【图像检索】基于傅里叶描述子的形状特征图像检索,matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于傅里叶描述子的形状特征图像检索&#xff0c;用matlab实现。 一、案例背景和算法…

企业数字化底座与数字化转型方案(可编辑的81页PPT)

方案介绍&#xff1a;在当今数字化转型的浪潮中&#xff0c;企业数字化底座与数字化转型方案是企业应对市场变化、提升竞争力的关键举措。通过构建数字化底座&#xff0c;实现数据的集中管理和共享&#xff1b;通过数字化转型方案的实施&#xff0c;推动企业的全面数字化改造。…

进阶版水仙花数水是指一个n位数,各个位数字的n次方之和等于该数字本身

两种方法&#xff1a; 第一种&#xff0c;是输入一个数值&#xff0c;判断是否为水仙花数 //打印水仙花数 //水仙花数是指一个n位数&#xff0c;各个位数字的n次方之和等于该数字本身 //如&#xff1a;1531^35^33^3 // //分析&#xff1a; //153/1015 //15/101 //1/100 #incl…

.whl文件下载及pip安装

以安装torch_sparse库为例 一、找到自己需要的版本&#xff0c;点击下载。 去GitHub的pyg-team主页中找到pytorch-geometric包。网址如下&#xff1a; pyg-team/pytorch_geometric​github.com/pyg-team/pytorch_geometric 然后点击如图中Additional Libraries位置的here&am…

Qt 多线程TCP客户端使用QTimer进行重连服务器———附带详细代码和讲解

文章目录 0 背景1 原理1.1 QThread的线程归属1.2 Qtimer使用1.3 TCP客户端使用 2 问题解决2.1 解决思路2.2 解决方法 3 完整的代码示例3.1 tcp_client类3.2 主界面类 附录参考 0 背景 在子线程中&#xff0c;使用Qtimer来进行定时重连TCP服务器&#xff0c;总是会出现跨线程创…

U盘显示未被格式化:深度解析、恢复策略与预防之道

现象透视&#xff1a;U显示未被格式化的迷局 在日常的数字生活中&#xff0c;U盘作为我们随身携带的数据仓库&#xff0c;承载着无数重要的文件与回忆。然而&#xff0c;当U盘突然弹出“未被格式化”的警告时&#xff0c;这份便捷瞬间转化为焦虑与不安。这一提示不仅意味着U盘…

uboot:源码分析-启动第一阶段-start.S解析

start.S引入 进入start.S文件中&#xff0c;发现57行中就是_start标号的定义处 SourceInsight中添加行号 在SI中&#xff0c;如果我们知道我们要找的文件的名字&#xff0c;但是我们又不知道他在哪个目录下&#xff0c;我们要怎样找到并打开这个文件&#xff1f;方法是在SI中先…

多重指针变量(n重指针变量)实例分析

0 前言 指针之于C语言&#xff0c;就像子弹于枪械。没了子弹的枪械虽然可以用来肉搏&#xff0c;却失去了迅速解决、优雅解决战斗的能力。但上了膛的枪械也非常危险&#xff0c;时刻要注意是否上了保险&#xff0c;使用C语言的指针也是如此&#xff0c;要万分小心&#xff0c;…

usemeno和usecallback区别及使用场景

1. useMemo 用途: useMemo 用于缓存计算结果。它接受一个函数和依赖项数组&#xff0c;只有当依赖项发生变化时&#xff0c;才会重新计算该函数的返回值。否则&#xff0c;它会返回缓存的值。 返回值: useMemo 返回的是函数执行后的结果。 使用场景: 当一个计算量大的函数在每…

Java面试篇基础部分-线程的基本方法

线程的基本方法有wait()、notify()、notifyAll()、sleep()、join()、yield()等等,这些方法都是用来控制线程的运行,并且可以实质性的影响到线程的状态变化情况。 让线程等待的方法:wait()方法 调用wait()方法的线程会进入到WAITING状态,只有等到其他线程通知或者线程被中…

【数据结构-差分】力扣1589. 所有排列中的最大和

有一个整数数组 nums &#xff0c;和一个查询数组 requests &#xff0c;其中 requests[i] [starti, endi] 。第 i 个查询求 nums[starti] nums[starti 1] … nums[endi - 1] nums[endi] 的结果 &#xff0c;starti 和 endi 数组索引都是 从 0 开始 的。 你可以任意排列…

【Java面向对象二】static的注意事项

文章目录 前言一、关于static的三个注意点总结 前言 记录static的学习注意事项。 一、关于static的三个注意点 1、类方法中可以直接访问类的成员&#xff0c;不可用直接访问实例成员。 2、实例方法中既可以直接访问类成员&#xff0c;也可以直接访问实例成员。 3、实例方法…

105.WEB渗透测试-信息收集-FOFA语法(5)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;104.WEB渗透测试-信息收集-FOFA语法&#xff08;4&#xff09; 还有一个能查看信息的地方…

linux下的分布式Minio部署实践

Linux下的分布式Minio部署实践 分布式Minio部署可以将多块硬盘&#xff08;位于相同机器或者不同机器&#xff09;组成一个对象存储服务&#xff0c;避免单机环境下硬盘容量不足、单点故障等问题。 1. 简介 在当前的云计算和大数据时代&#xff0c;IT系统通常的设计理念都是…

英伟达Jim Fan预测:未来2~3年机器人将迎来“GPT-3时刻”

在这个科技不断进步的时代&#xff0c;我们终将迎来“与机器人共存”的未来。你认为&#xff0c;未来会是人机和平共处&#xff0c;还是《终结者》式未来&#xff1f; 随着科技发展&#xff0c;这个未来似乎近在咫尺。昨日外媒 The Decoder 发文报道&#xff0c;在最近的一次红…