C++Date类的实现

目录

前言:

1.显示日期

2.构造函数与获取某年某月的日期的函数

3.日期比较

4.日期加减天数

5.日期减日期

6.前置后置++与--

7.完整代码

8.测试

总结:

感谢支持!


前言:

结合了前面的内容的学习,本篇来对之前的内容像运算符重载等进行应用,完成日期类的实现,具体功能大致包括对日期的加减比较,显示日期等。

1.显示日期

调用成员函数打印日期:

void Date::Print() const
{
	cout << _year << "/" << _month << "/" << _day << endl;
}

对流插入<<进行重载,完成对日期类的打印:

 定义文件中:

ostream& operator<<(ostream& out, const Date& d) 
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}

声明文件中:

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

 为什么这里要用友元函数:

由于我们要使用的格式为例如,cout<<d1,如果放到成员函数中,由于对象调用成员函数会传对象的地址并在成员函数中用this指针接收,所以第一个参数只能是Date* this,也只能d1<<cout这样调用。

但是我们如果仅仅定义为一个普通函数就没法访问到类中的私有成员变量了,而且不能为了一个函数就让成员函数放为私有的,所以我们这里使用友元函数,既可以访问成员变量,也可以调整参数的顺序。

2.构造函数与获取某年某月的日期的函数

声明文件中:

	Date(int year = 1900, int month = 1, int day = 1);
	int GetMonthDay(int year, int month) const;

注意构造函数的缺省要在声明中给(如果声明和定义的缺省值不同,编译器无法确定,放在声明中也减少了其他源文件重复定义)。

定义文件中:

int Date::GetMonthDay(int year, int month) const
{
	assert(month > 0 && month < 13);
	int MonthArray[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 29;//闰年
	}
	else
	{
		return MonthArray[month];
	}
}

Date::Date(int year, int month, int day)
{
	if (year > 0 && (month > 0 && month < 13) && (day > 0 && day <= GetMonthDay(month, day)))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		cout << "初始化日期非法" << endl;
	}

}

1.因为有闰年平年之分,还有不同的月的天数不同,所以我们要定义一个函数来获取具体到哪年哪月的具体的天数。

2.获取天数用一个数组来确定,方便下标与内容对应,多加一位;其次就是单独判断闰年的二月是29天,如果是,那就直接返回,如果不是,就返回对应下标的天数。

3.构造函数判断一下日期的合法性。 

3.日期比较

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

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

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);
}

可以先实现等于和小于的逻辑,其它的逻辑直接复用即可。 

4.日期加减天数

Date& Date::operator+=(int day) 
{
	if (day < 0)
	{
		*this -= -day;//+=一个负的,就是让它走-=一个正的逻辑
		return *this;
	}
	_day += day;

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

	return *this;
}

Date Date::operator+(int day) const
{
	Date tmp(*this);
	tmp += day;//复用,变得更简单

	//tmp._day += day;
	//while (tmp._day < GetMonthDay(tmp._year, tmp._month))
	//{
	//	tmp._day -= GetMonthDay(tmp._year, tmp._month);
	//	++tmp._month;
	//	if (tmp._month == 13)
	//	{
	//		tmp._year++;
	//		tmp._month = 1;
	//	}
	//}
	return tmp;
}

Date& Date::operator-=(int day)
{
	Date tmp(*this);
	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) const
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}

 1.首先区分+=和-=与+和-的区别,+=和-=是会对原内容进行修改,也就是对对象进行修改,所以用引用返回,直接返回this指针,还能减少返回时产生的拷贝;而对于+和-来说,不能改变原有的对象,所以先调用编译器默认生成的拷贝构造来对对象进行一次拷贝(这里只有浅拷贝,不会出错),然后再对拷贝的对象复用+=或者-=的逻辑,再返回这个拷贝的对象即可,所以这里需要用一个返回值接收这个结果才能看出来。

2.要注意如果对天数进行操作时,天数为-怎么办。如果为负,在+=里面,就是要转换为-=了,所以写一句*this-=-day即可转换成去调用,因为day本身就是负的,所以就去调用*this-=day了;在-=则相反。

3.在+=中,我们要还要判断,当天数+的超过了这个月的天了,我们就要往下个月加了,如果加到下个月还多,那就再往下个月加,所以使用一个循环来实现,如果月加到了13,就要加到下一年去,并且让月再从一月开始,+也要考虑这个问题,但是我们复用了+=的逻辑,就不考虑了。

4.在-=中,我们要判断如果天数减的变为了负的,那就要往上一个月去借,然后让天数加上这个月的天数,如果借的还不够,继续借,所以使用循环来实现,注意如果月减到了0,就要往上一年借,并让月从12开始。-直接复用即可。

5.也可以先完成+-的逻辑,+=与-=再复用:
 

//如果先实现了+的逻辑,+=也可复用+的逻辑
//*this=*this+day;但是这个会先调operator+的函数,再调自动生成的operator赋值函数,所以建议使用第一种

这样就多了拷贝了,所以建议先实现+=与-=。

5.日期减日期

日期减日期可以有两种方法,可以先获取两个日期距离所在年的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;
}

flag用来确定正负,n用来计算相差多少天。先假设左边的日期大,然后比较,如果右边大,交换顺序,并且右边大减出来肯定是负的,所以再让flag设为-1,然后让n计数,看相差多少天,然后返回天数*正反号即可。

6.前置后置++与--

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

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

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

1.前置复用之前+=与-=的逻辑,直接返回这个修改后的对象;而后置是先拷贝,再对原对象进+=和-=的复用,再返回没有改变的拷贝的对象,这样接收返回值的时候,接收的就是没有改变的对象,但是原来的对象已经修改了,就起到了后置的效果。

2.编译器为了区分前置后置,在调用后置的时候,会传一个参数,可能是一个整形0,可能是其他的,所以重载的时候写一个int参数,这是编译器自动传的,不用我们自己传,自己传也行。

7.完整代码

定义文件:

#define _CRT_SECURE_NO_WARNINGS
#include "Date.h"

int Date::GetMonthDay(int year, int month) const
{
	assert(month > 0 && month < 13);
	int MonthArray[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 29;//闰年
	}
	else
	{
		return MonthArray[month];
	}
}

Date::Date(int year, int month, int day)
{
	if (year > 0 && (month > 0 && month < 13) && (day > 0 && day <= GetMonthDay(month, day)))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		cout << "初始化日期非法" << endl;
	}

}

void Date::Print() const
{
	cout << _year << "/" << _month << "/" << _day << endl;
}

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

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

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);
}

Date& Date::operator+=(int day) 
{
	if (day < 0)
	{
		*this -= -day;//+=一个负的,就是让它走-=一个正的逻辑
		return *this;
	}
	_day += day;

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

	return *this;
}

Date Date::operator+(int day) const
{
	Date tmp(*this);
	tmp += day;//复用,变得更简单

	//tmp._day += day;
	//while (tmp._day < GetMonthDay(tmp._year, tmp._month))
	//{
	//	tmp._day -= GetMonthDay(tmp._year, tmp._month);
	//	++tmp._month;
	//	if (tmp._month == 13)
	//	{
	//		tmp._year++;
	//		tmp._month = 1;
	//	}
	//}
	return tmp;
}

Date& Date::operator-=(int day)
{
	Date tmp(*this);
	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) const
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}

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;
}


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

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

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

ostream& operator<<(ostream& out, const Date& d) 
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}

声明文件:

#pragma once
#include <iostream>
#include <assert.h>

using namespace std;

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);
public:
	Date(int year = 1900, int month = 1, int day = 1);
	int GetMonthDay(int year, int month) const;
	void Print() 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;
	bool operator!=(const Date& d) const;

	Date& operator+=(int day);
	Date operator+(int day) const; 
	Date& operator-=(int day);
	Date operator-(int day) const;
	int operator-(const Date& d) const;

	Date& operator++();
	Date operator++(int);
	Date& operator--();
	Date operator--(int);

	
	

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

这样的成员函数没对成员变量进行修改的都加上了const修饰,方便不是const的对象和const的对象都能调用。

8.测试

#define _CRT_SECURE_NO_WARNINGS
#include "Date.h"

void TestDate1()
{
	Date d1(2024, 4, 4);
	Date d2(2023, 4, 4);
	
	Date ret1=++d1;
	cout << d1;
	cout << ret1;
	
	Date ret2=d1++;
	cout << d1;
	cout << ret2;
	cout << endl;

	Date ret3=d1--;
	cout << d1;
	cout << ret3;
	
	Date ret4=--d1;
	cout << d1;
	cout << ret4;

	d1.Print();

}

void TestDate2()
{
	Date d1(2024, 4, 4);
	Date d2(2023, 4, 4);

	Date ret1=d1 + 100;
	cout << d1;
	cout << ret1;

	d1 += 100;
	cout << "d1此时为:" << d1;

	Date ret2=d2 - 100;
	cout << d2;
	cout << ret2;

	d2 -= 100;
	cout << "d2此时为:" << d2;

	cout << (d1 - d2) << endl;;
	cout << (d2 - d1) << endl;;

}

void TestDate3()
{
	Date d1(2024, 4, 4);
	Date d2(2023, 4, 4);

	cout << (d1 > d2) << endl;
	cout << (d1 < d2) << endl;
	cout << (d1 >= d2) << endl;
	cout << (d1 <= d2) << endl;
	cout << (d1 != d2) << endl;
	cout << (d1 == d2) << endl;

}

int main()
{
	TestDate3();
	return 0;
}

 

 

总结:

感谢支持!

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

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

相关文章

面试篇:杂乱篇

String s " "; 1. String类的常用方法有哪些&#xff1f; s.length()&#xff1a; 返回字符串长度s.substring()&#xff1a; 截取字符串s.split()&#xff1a; 分割字符串s.equlas()&#xff1a; 字符串比…

Ai智能生成图片神器,多种风格任你选,探索无限可能的视觉盛宴

在数字化浪潮中&#xff0c;图片已成为我们表达创意、传递情感、展示品牌的重要工具。然而&#xff0c;不是每个人都有专业的设计背景&#xff0c;也不是每个创作者都能轻松驾驭各种风格。这时&#xff0c;一款强大而灵活的AI智能生成图片神器应运而生&#xff0c;它将为你的创…

Vol.34 Good Men Project:一个博客网站,每月90万访问量,通过付费订阅和广告变现

今天给大家分享的案例网站是&#xff1a;Good Men Project&#xff0c;这是一个专门针对男性成长的博客网站&#xff0c;内容包括人际关系、家庭、职业发展等话题。 它的网址是&#xff1a;The Good Men Project - The Conversation No One Else Is Having 流量情况 我们先看…

【python实战】--提取所有目录下所有Excel文件指定列数据

系列文章目录 文章目录 系列文章目录前言一、问题描述二、python代码1.引入库 总结 前言 一、问题描述 需要提取指定路径下所有excel文件中指定一列数据&#xff0c;汇总到新文件&#xff0c;&#xff08;逐列汇总&#xff09; 二、python代码 1.引入库 代码如下&#xff08…

vue弹出的添加信息组件中 el-radio 单选框无法点击问题

情景描述:在弹出的添加信息的组件中的form中有一个单选框,单选框无法进行点击切换 原因如下: 单选框要求有个默认值,因为添加和更新操作复用同一个组件,所以我在初始化时对相关进行了判定,如果为空则赋初始值 结果这样虽然实现了初始值的展示,但是就是如此造成了单选框的无法切…

【MATLAB源码-第176期】基于matlab的16QAM调制解调系统频偏估计及补偿算法仿真,对比补偿前后的星座图误码率。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 在通信系统中&#xff0c;频率偏移是一种常见的问题&#xff0c;它会导致接收到的信号频率与发送信号的频率不完全匹配&#xff0c;进而影响通信质量。在调制技术中&#xff0c;QPSK&#xff08;Quadrature Phase Shift Keyin…

NIUSHOP完美运营版商城 虚拟商品全功能商城 全能商城小程序 智慧商城系统 全品类百货商城

完美运营版商城/拼团/团购/秒杀/积分/砍价/实物商品/虚拟商品等全功能商城 干干净净 没有一丝多余收据 还没过手其他站 还没乱七八走的广告和后门 后台可以自由拖曳修改前端UI页面 还支持虚拟商品自动发货等功能 挺不错的一套源码 前端UNIAPP 后端PHP 一键部署版本 源码免费…

基于SpringBoot+Vue前后端分离高校就业信息管理系统的设计与实现+毕业论文

介绍 随着中国大力发展教育事业&#xff0c;在校大学生的数量不断增多&#xff0c;导致大学毕业生的数量也不断增多&#xff0c;就业形势日趋严峻。开发一套符合就业形势的高校就业信息管理系统是非常必要的&#xff0c;这样既能提高就业管理部门的管理水平&#xff0c;又能通…

014——超声波模块驱动开发Plus(基于I.MX6uLL、SR04和poll机制)

目录 一、基础知识 二、分析为什么打印会影响中断 三、驱动程序 四、应用程序 五、验证及其它 一、基础知识 013——超声波模块驱动开发&#xff08;基于I.MX6uLL与SR04&#xff09;-CSDN博客 二、分析为什么打印会影响中断 asmlinkage __visible int printk(const ch…

Loadrunner的使用

Loadrunner的使用 选项公网测试地址&#xff1a;http://cfgjt.cn:8981/devt-web 用户名admin&#xff0c;密码11111111 1.Loadrunner介绍 ​ LoadRunner&#xff0c;是一种预测系统行为和性能的负载测试工具。通过模拟上千万用户实施并发负载及实时性能监测的方式来确认和查…

Ubuntu部署BOA服务器

BOA服务器概述 BOA是一款非常小巧的Web服务器&#xff0c;源代码开放、性能优秀、支持CGI通用网关接口技术&#xff0c;特别适合用在嵌入式系统中。 BOA服务器主要功能是在互联嵌入式设备之间进行信息交互&#xff0c;达到通用网络对嵌入式设备进行监控&#xff0c;并将反馈信…

【c/c++】深入探秘:C++内存管理的机制

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们详细讲解c中的动态内存管理 目录 1.C/C内存分布2.C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free3.c内存管理方式3.1new/delete对内…

LeetCode-199. 二叉树的右视图【树 深度优先搜索 广度优先搜索 二叉树】

LeetCode-199. 二叉树的右视图【树 深度优先搜索 广度优先搜索 二叉树】 题目描述&#xff1a;解题思路一&#xff1a;广度优先搜索解题思路二&#xff1a;深度优先搜索解题思路三&#xff1a;0 题目描述&#xff1a; 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它…

股权激励和期权激励对比辨析

文章目录 概念定义 收益方式 风险评估 应用和分析 股权激励和期权激励&#xff0c;两者的区别是什么&#xff0c;本文就来梳理对比一下。 概念定义 股权激励&#xff0c;是指上市公司以本公司股票为标的&#xff0c;对其董事、高级管理人员及其他员工进行的长期性激励。取得…

微服务(基础篇-008-es、kibana安装)

目录 05-初识ES-安装es_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1LQ4y127n4?p81&vd_source60a35a11f813c6dff0b76089e5e138cc 1.部署单点es 1.1.创建网络 1.2.加载镜像 1.3.运行 2.部署kibana 2.1.部署 2.2.DevTools 3.安装IK分词器 3.1.在线安装ik…

程序员们应注意的行业特有的法律问题

大家好&#xff0c;我是不会魔法的兔子&#xff0c;是一枚执业律师&#xff0c;持续分享技术类行业项目风险及预防的问题。 一直以来兔子都在以大家做项目时候会遇到的风险问题做分享&#xff0c;最近有个念头一直挥之不去&#xff0c;就是要不要给我们广大的程序员们也分享一…

一文彻底搞懂ZooKeeper选举机制

文章目录 1. ZooKeeper 集群2. ZooKeeper 启动3. ZooKeeper 选举机制4. Follower&#xff08;跟随者&#xff09;和Candidate&#xff08;候选者&#xff09;节点区别5. Leader节点挂掉期间写操作是否会丢失 1. ZooKeeper 集群 ZooKeeper 是一个分布式的开源协调服务&#xff…

Node.js------模块化

◆ 能够说出模块化的好处◆ 能够知道 CommonJS 规定了哪些内容◆ 能够说出 Node.js 中模块的三大分类各自是什么◆ 能够使用 npm 管理包◆ 能够了解什么是规范的包结构◆ 能够了解模块的加载机制 一.模块化的基本概念 1.模块化 模块化是指解决一个复杂问题时&#xff0c…

基于SpringBoot+Thymeleaf的学生会管理系统

在这里插入图片描述 在这里插入图片描述

MYSQL——索引概念索引结构

索引 索引是帮助数据库高效获取数据的排好序的数据结构。 有无索引时&#xff0c;查询的区别 主要区别在于查询速度和系统资源的消耗。 查询速度&#xff1a; 在没有索引的情况下&#xff0c;数据库需要对表中的所有记录进行扫描&#xff0c;以找到符合查询条件的记录&#…