日期类代码实现-C++

news2024/11/24 14:53:13

一、目标

        通过前面对类和对象的介绍我们可以自己通过C++代码初步实现一个简单的日期类。

实现的主要操作有:

1.日期类的构造函数

2.日期类的拷贝构造函数(在头文件中实现)

3.日期类的比较运算符重载

4.日期类的计算运算符重载

5.流插入运算符重载。

二、总体思路

        首先,我这里采用的是分文件编程的方式来实现的日期类。

分别为:

1.头文件:Date.h

        该文件的主要目的是对上述目标所要实现的所有操作进行函数的声明。同时,还要包含在

源文件Date.cpp 中定义时所需要用到的头文件函数。

2.源文件:Date.cpp

        该文件的目的主要是用于对 头文件Date.h 所声明的所有函数进行定义,从而完成各个函数所要实现的操作。

3.源文件:Test.cpp

        该文件的目的主要是用于检测 源文件Date.cpp 中定义的函数是否能正常够使用并且达到所要实现的操作。

三、代码实现及具体思路

1.头文件:Date.h

        通过上面思路的介绍,我们可以知道,我们的目的是创建一个日期类,然后在日期类中自我声明:日期类的构造函数、日期类的比较运算符重载、日期类的计算运算符重载以及流插入运算符重载。并实现拷贝构造函数。

注意:通过我们前面对类和对象的介绍可知,因为在实现日期类过程中,我们没有动态申请空间,所以我们只需使用编译器默认生成的析构函数就可以,因此,我们不需要自己再定义一个析构函数)

代码如下:

#pragma once

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

using namespace std;
class Date
{

public:
	Date(int year = 1, int month = 1, int day = 1);
	void Print()const
	{
		cout << _year << '-' << _month << '-' << _day << endl;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	//日期类的比较运算符的重载
	bool operator<(const Date& x) const;
	bool operator==(const Date& x) const;
	bool operator<=(const Date& x) const;
	bool operator>(const Date& x) const;
	bool operator>=(const Date& x) const;
	bool operator!=(const Date& x) const;

	//日期类的计算运算符的重载
	int Get_MonthDay(int year,int month);		//获取该月份的天数

	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);		//后置--

	int operator-(const Date& x) const;

	// 流插入不能写成成员函数?
	// 因为Date对象默认占用第一个参数,就是做了左操作数
	// 写出来就一定是下面这样子,不符合使用习惯
	//d1 << cout; // d1.operator<<(cout); 
	//void operator<<(ostream& out);
	
	// 友元函数声明
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& out, const Date& x);
istream& operator>>(istream& in, Date& x);

2.源文件:Date.cpp

        对于实现下面函数,我们需要首先定义一个获取当前月份天数的函数

代码实现:

//因为平年闰年的2月天数不一样所以我们需定义一个获取月份的函数来解决这一问题
int Date::Get_MonthDay(int year, int month)		//获取该月份的天数
{
	static int daysArr[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 daysArr[month];
	}
}

1.日期类的构造函数

 思路:

        我们在通过日期类构造函数初始化所定义的日期时,我们需要判断我们所定义的日期是否合法,若不合法,则需要返回并提示

代码实现:

Date::Date(int year, int month, int day)
{
    //判断所初始化的日期是否合法
	if (month > 0 && month < 13
		&&day>=1&&day<= Get_MonthDay(year, month))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}
}

2.日期类的比较运算符重载

思路:

        对于比较类的运算符重载来说,因为比较运算符具有互斥性,所以我们只需定义出 < 运算符重载和 == 运算符重载,然后其他运算符复用上面所定定义的两个运算符即可。并且在比较的同时,我们不会改变参数的值,所以我们可以在函数尾部加const用于修饰内部的this指针,这样的话,const修饰的类型我们也可以通过比较运算符来比较。

代码实现:

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

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

bool Date::operator<=(const Date& x) const
{
	//复用上面定义的重载运算符:< , ==
	return *this < x || *this == x;
}

bool Date::operator>(const Date& x) const
{
	//复用上面定义的重载运算符:<=
	return !(*this <= x);
}

bool Date::operator>=(const Date& x) const
{
	//复用上面定义的重载运算符:> , ==
	return *this > x || *this == x;
}

bool Date::operator!=(const Date& x) const
{
	//复用上面定义的重载运算符:==
	return !(*this == x);
}

3.日期类的计算运算符重载

思路:

        对于日期类的计算运算符重载的定义,我们可以先定义 += 运算符重载和 -= 运算符重载,然后其他运算符重载的定义我们可以复用这两个运算符重载,从而实现各个运算符所要实现的目的。

代码实现:

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

Date Date::operator+(int day)const
{
	if (day < 0)
	{
		return *this - (-day);
	}
	//复用上面定义的重载运算符:+=
	Date tem(*this);
	tem+= day;
	return tem;
}

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

Date Date::operator-(int day)const
{
	if (day < 0)
	{
		return *this + (-day);
	}
	//复用上面定义的重载运算符:-=
	Date tem(*this);
	tem -= day;
	return tem;
}

Date& Date::operator++()
{
	//复用上面定义的重载运算符:+=
	*this += 1;
	return *this;
}

Date Date::operator++(int)
{
	//复用上面定义的重载运算符:+
	Date tem = *this;
	*this += 1;
	return tem;
}

Date& Date::operator--()
{
	//复用上面定义的重载运算符:+=
	*this -= 1;
	return *this;
}

Date Date::operator--(int)
{
	//复用上面定义的重载运算符:+
	Date tem = *this;
	*this -= 1;
	return tem;
}

        实现两个日期之间相减求天数时,我们可以先判断哪个日期大,从而确定出所求的天数是正数还是负数,即用flage的正负来实现。接着我们定义一个n来统计天数,然后我们通过while循环,++最小的日期,并且++天数直到最小日期和最大日期相等的时候结束,这时候我们返回n*flage的值即是所求天数。

int Date::operator-(const Date& x) const
{
	Date max = *this;
	Date min = x;
	int flage = 1;
	if (*this < x)
	{
		max = x;
		min = *this;
		flage = -1;
	}
	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}
	return n * flage;
}

4.流插入运算符重载。

思路:

        对于日期类使用系统中的流插入(只能插入内置类型)时并不能实现所期望的操作,因为日期类是自定义类型,所以我们就需要自己定义一个流插入来实现这个操作

	// 流插入不能写成成员函数?
	// 因为Date对象默认占用第一个参数,就是做了左操作数
	// 写出来就一定是下面这样子,不符合使用习惯
	//d1 << cout; // d1.operator<<(cout); 
	//void operator<<(ostream& out);

因此,这里我们通过友元函数,在全局中定义流插入的运算符重载

代码实现:

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

	return out;
}

istream& operator>>(istream& in, Date& x)
{
	int year, month, day;
	in >> year >> month >> day;

	if (month > 0 && month < 13
		&& day > 0 && day <= x.Get_MonthDay(year, month))
	{
		x._year = year;
		x._month = month;
		x._day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}

	return in;
}

3.源文件:Test.cpp

Test1:

用于检测日期类的比较运算符的重载

void Test1()		//用于检测日期类的比较运算符的重载
{
	Date s1(2005, 2, 16);
	Date s2(2024, 8, 12);
	cout << "bool operator<(const Date& x) const:" << (s1 < s2) << endl;
	cout << "bool operator==(const Date& x) const:" << (s1 == s2) << endl;
	cout << "bool operator<=(const Date& x) const:" << (s1 <= s2) << endl;
	cout << "bool operator>(const Date& x) const:" << (s1 > s2) << endl;
	cout << "bool operator>=(const Date& x) const:" << (s1 >= s2) << endl;
	cout << "bool operator!=(const Date& x) const:" << (s1 != s2) << endl;
}

Test2:

用于检测日期类的计算运算符的重载:+= , +

void Test2()		//用于检测日期类的计算运算符的重载:+= , +
{
	Date s1(2005, 2, 16);
	s1.Print();
	s1 += 10000;
	s1.Print();

	Date s2(2005, 2, 16);
	s2.Print();
	Date s3=s2+10000;
	s3.Print();
}

Test3:

用于检测日期类的计算运算符的重载:-= , -

void Test3()		//用于检测日期类的计算运算符的重载:-= , -
{
	Date s1(2005, 2, 16);
	s1.Print();
	s1 -= 1000;
	s1.Print();

	Date s2(2005, 2, 16);
	s2.Print();
	Date s3 = s2 - 1000;
	s3.Print();
}

Test4:

用于检测日期类的计算运算符的重载:--

void Test4()		//用于检测日期类的计算运算符的重载:--
{
	Date s2(2005, 2, 16);
	Date s3(2005, 2, 16);
	Date s4;
	s4=s2--;
	s4.Print();

	s4 = --s3;
	s4.Print();
}

Test5:

用于检测日期类的计算运算符的重载:++

void Test5()		//用于检测日期类的计算运算符的重载:++
{
	Date s2(2005, 2, 16);
	Date s3(2005, 2, 16);
	Date s4;
	s4 = s2++;
	s4.Print();

	s4 = ++s3;
	s4.Print();
}

Test6:

用于检测日期类之间的计算运算符的重载:-

void Test6()		//用于检测日期类之间的计算运算符的重载:-
{
	Date s1(2005, 2, 16);
	Date s2(2024, 8, 13);
	cout << "int operator-(const Date& x) const:" << (s1 - s2) << endl;
}

Test7:

用于检测日期类之间的计算运算符的重载:<< , >>

void Test7()		//用于检测日期类之间的计算运算符的重载:<< , >>
{
	Date s1;
	cin >> s1;
	cout << s1 << endl;
	cout << s1 + 100 << endl;
}

四、结语:

         上述内容,即是我个人对C++日期类的个人见解及代码实现。若有大佬发现哪里有问题可以私信或评论指教一下。非常感谢各位uu们的点赞,关注,收藏,还望各位多多关照,让我们一起进步吧!

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

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

相关文章

Python 爬数据案例 客户端服务端http请求 推荐 【进阶篇 2 】

网络爬虫数据原来这么简单&#xff01;&#xff01;&#xff01; 前面已经总结了关于python的面向对象继承多态的知识&#xff0c;这里主要是模块、读写文件、http请求网络数据以及如何获取网络数据知识。 网络爬虫是典型的应用程序&#xff0c;它的工作原理就是通过不断的请…

VBA语言専攻T3学员领取资料通知0817

T3学员领取资料通知0817 各位学员∶本周MF系列VBA技术资料增加681-690讲&#xff0c;T3学员看到通知后请免费领取,领取时间8月16日晚上19:00-8月17日中午12:00。本次增加内容&#xff1a; MF691:按所选范围对行进行分组显示 MF692:查找所给范围内的重复项 MF693:文本框Text…

python非交互连接mysql+mycat读写分离实现

python非交互连接mysql >>>import pymysql >>>connpymysql.connect(host"192.168.118.57",port3306,database"test",user"root",password"root") >>> cursorconn.cursor() >>> cursor.execut…

基于springboot的智能家居系统

TOC springboot198基于springboot的智能家居系统 研究背景与现状 时代的进步使人们的生活实现了部分自动化&#xff0c;由最初的全手动办公已转向手动自动相结合的方式。比如各种办公系统、智能电子电器的出现&#xff0c;都为人们生活的享受提供帮助。采用新型的自动化方式…

day22 Java基础——方法(干货)

day22 Java基础——方法 在Java中&#xff0c;方法是一段组织好的、可重复使用的代码块&#xff0c;用于执行一个特定的操作。方法提供了一种封装代码的方式&#xff0c;使得代码模块化&#xff0c;便于管理和重用。以下是关于Java中方法的一些基本介绍&#xff1a; 文章目录…

对话图像编辑研究综述

MGIE&#xff1a;MLLM 引导图像编辑&#xff08;ICLR 2024&#xff09; https://mllm-ie.github.io/ 利用 MLLM 来增强基于指令的图像编辑 (“what will this image be like if [instruction]” &#xff0c;来重写)。 训练好后&#xff0c;大视觉语言模型直接推导出简洁明确…

FreeRTOS队列(下)

文章目录 一、使用队列实现多设备输入1、增加旋转编码器2、使用队列集执行任务3、增加姿态控制&#xff08;使用MPU6050控制挡球板&#xff09; 二、队列实验_分发数据给多个任务(赛车游戏)三、传输大块数据四、示例&#xff1a;邮箱&#xff08;Mailbox&#xff09;五、队列集…

远程桌面你的凭据不工作解决方法

如果遇到“你的凭据不工作”的提示&#xff0c;请首先确认您输入的凭据是否正确。如果确认无误但仍然出现Windows远程桌面凭据不工作的提示&#xff0c;这可能是由于Windows安全设置的问题所导致的。要解决远程桌面连接提示你的凭据不工作这一问题&#xff0c;您可以尝试以下解…

qemu的VNC协议(RFB协议)

1、握手 1.1、服务器收到客户端TCP连接上后&#xff0c;服务器发送RFB的版本&#xff1a; 52 46 42 20 30 30 33 2e 30 30 38 0a RFB 003.008\n 1.2、客户端收到后回复&#xff1a; 52 46 42 20 30 30 33 2e 30 30 38 0a RFB 003.008\n 2、安全认证 2.1、服务器发送支…

MySQL数据库之part2

一、索引原理与慢查询优化 一&#xff09;介绍 1、为何需要有索引 一般的应用系统&#xff0c;读写比例是10:1左右&#xff0c;而且插入操作和一般的更新操作很少出现性能问题。在生产环境中&#xff0c;我们遇到最多的、也是最容易出问题的还是一些负责的查询操作。因此查询语…

密码学基础---椭圆曲线一文打尽

1.ECC简介及密钥生成 当前公认安全有效的三大类公钥密钥体制分别为基于大数因子分解难题(RSA)、离散对数难题(DSA)和椭圆曲线离散对数&#xff08;ECC&#xff09;难题的密码体制。 最初RSA由于其容易理解被广泛运用&#xff0c;但随着计算机性能的提升&#xff0c;要保证RS…

JavaScript学习笔记(十三):网络请求JS AJAX

1、AJAX - XMLHttpRequest 对象 1.1 XMLHttpRequest 对象是 AJAX 的基石。 创建 XMLHttpRequest 对象定义回调函数打开 XMLHttpRequest 对象向服务器发送请求 1.2 XMLHttpRequest 对象 所有现代浏览器都支持 XMLHttpRequest 对象。 XMLHttpRequest 对象可用于在后台与 Web…

【mysql】MySQL的数据库简单搭建

文章目录 前言基础知识数据库数据表数据表结构记录&#xff08;数据&#xff09; 数据类型数值类型字符串类型日期类型二进制类型其他数据类型 约束where子句其他条件 order by 语句 &#xff08;排序&#xff09;group by语句&#xff08;分组&#xff09; 数据库操作新建数据…

漏洞挖掘 | EDU拿敏感信息的骚思路

1. 寻找资产 在进行edu漏洞挖掘的时候&#xff0c;我们常常遇到统一认证平台&#xff0c;账号是学号&#xff0c;密码是身份证后6位&#xff08;甚至是更复杂的密码&#xff09;&#xff0c;同时找到这两者的几率很小&#xff0c;所以我们把关注点放在微信小程序中&#xff0c…

15 个高难度 Java 面试题及答案

一、企业聘用指南 聘用合适的 Java 开发人员对您的业务至关重要。聘用不当可能会导致代码效率低下、错过最后期限以及团队活力不佳。这就是为什么在聘用候选人之前必须彻底审查每位候选人的原因。这个过程的一部分是在面试 Java 开发人员候选人时提出正确的问题。 通过我们列…

OK-COIN : 总统大选成为比特币牛市的导火索

每一届总统大选&#xff0c;都将带动比特币进入牛市行情&#xff0c;还有三个多月时间&#xff0c;现在比特币经过底部针震荡整理后&#xff0c;形成了坚实的“双针探底”形态&#xff0c;确认比特币底部形成&#xff0c;随后迎来了非常强势的单边趋势性行情机会 &#xff0c;相…

IDEA关键词全局检索-之jar包

正常没有下载到源码的jar包&#xff0c;是无法检索到.class编译文件中内容的 repository本地仓库中&#xff0c;也是没有源码的 《检索步骤》 1、首先&#xff0c;下载源码 - 可以配置maven自动下载所有jar包的源码&#xff08;再同样配置File-NewProjectsSetup-Settingsfor…

CAN总线学习笔记

1 CAN总线简介 CAN&#xff08;Controller Area Network&#xff09;控制器局域网。 2 电平表示 CAN 总线用两根数据线传输数据&#xff0c;使用差分信号。 2.1 显性电平–低电平–逻辑零 当单片机发送逻辑0信号时&#xff0c;CAN转换芯片输出端会输出一个3.5V信号和一个…

【大模型理论篇】GPT系列预训练模型原理讲解

1. 背景简述 GPT的全称是Generative Pre-Trained Transformer&#xff0c;以Transformer为基础模型&#xff08;可以看Transformer的原理解析&#xff09;&#xff0c;先后迭代了GPT-1【1】&#xff0c;GPT-2【2】&#xff0c;GPT-3【3】、GPT3.5(InstructGPT)【10】、GPT4。…

【直播预告】智能机器人赛道技术培训定档8.20

在不远的将来&#xff0c;机器人可能会成为我们日常生活中不可或缺的伙伴&#xff0c;它们在工业生产线上精准操作&#xff0c;在家庭中提供温馨陪伴&#xff0c;甚至在探索未知领域中担当先锋。而现在&#xff0c;正是我们拥抱这一未来&#xff0c;深入了解并掌握智能机器人技…