日期类(Date)的实现 (C++版)

                   

                       

                                         🌹个人主页🌹喜欢草莓熊的bear

                                                🌹专栏🌹:C++入门

 

目录

前言

一、Date的头文件,包含函数声明

二、 Date.cpp

2.1 int GetMonthDay(int year, int month)

2.2 bool Check()

2.3 Date& operator+=(int day)

2.4 Date& operator-=(int day)

2.5 Date& operator++()

2.6 Date operator++(int)

2.7 bool operator < (const Date& d)const

2.8 bool operator==(const Date& d)const

2.9 int operator-(const Date& d)const

2.10 ostream& operator<<(ostream& out, const Date& d)

2.11 istream& operator>>(istream& i, Date& d)

三、 完整代码

Date.cpp

总结


前言

hello ,大家又来跟着bear学习了。一起奔向更好的自己

一、Date的头文件,包含函数声明

Date.h

#pragma once
#include<iostream>
#include<cmath>
#include <cassert>
using namespace std;

class Date

{
public:

	friend ostream& operator<<(ostream& out, const Date& d);//友源函数的声明
	friend istream& operator>>(istream& in, Date& d);//友源函数的声明
	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		int day = arr[month];
		if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0))//润年2月多一天
		{
			day++;
		}

		return day;
	}

	// 全缺省的构造函数
	Date(int year = 1949,int month = 10,int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;

		if (!Check())
		{
			cout << "非法日期输入!";
			Print();
		}
	}

	void Print()const;//打印函数

	bool Check();//检查函数

	// 全缺省的构造函数

	// 拷贝构造函数
  // d2(d1)
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
	//Date& operator=(const Date& d);

	// 析构函数
	~Date()
	{
		_year = 2024;
		_month = 1;
		_day = 1;
	}

	// 日期+=天数
	Date& operator+=(int day);

	// 日期+天数
	Date operator+(int day)const;

	// 日期-天数
	Date operator-(int day)const;

	// 日期-=天数
	Date& operator-=(int day);

	// 前置++
	Date& operator++();

	// 后置++
	Date operator++(int);

	// 后置--
	Date operator--(int);

	// 前置--
	Date& operator--();

	// >运算符重载
	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;

	//void operator<<(ostream& out):


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

ostream& operator<<(ostream& out, const Date& d);//输出流操作符重载
istream& operator>>(istream& i, Date& d);//输入流操作符重载

二、 Date.cpp

2.1 int GetMonthDay(int year, int month)

GetMonthDay函数的功能是:// 获取某年某月的天数

其中就要考虑到润年的二月比正常的多一天,这里我们的想法是使用一个静态数组来储存每个月的天数。

static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

这里多定义一个空间,方便下标和月份对应。 

闰年的判断条件我们在C语言里面就学习过了,那就是能被4整除且不能被100整除 或者 被400整除。转换成代码就是

year % 4 == 0 && year % 100 != 0 || year % 400 == 0

最主要的两个功能已经实现了我们就完整的实现一下这个获取某年某月的天数函数

// 获取某年某月的天数
int GetMonthDay(int year, int month)
{
	assert(month > 0 && month < 13);
	static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	int day = arr[month];
	if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0))//润年2月多一天
	{
		++day;
	}

	return day;
}

 这里使用静态的数组原因就是在调用该函数的时候不用多次申请空间。因为静态是结束是程序周期结束。

还有把month = 2 也是使得程序更加高效。这个函数还是很简单的。

2.2 bool Check()

bool Check()作用:检查日期是否合法,因为不可能出现6月31日的日期。

检查的对象有month 和 day。

_month < 1 ||  _month > 12


_day < 1 ||  _day > Date::GetMonthDay(_year, _month)
bool Date::Check()//检查日期是否合法
{
	if (_month < 1 || _month > 12 || _day < 1
		|| _day > Date::GetMonthDay(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

2.3 Date& operator+=(int day)

Date& operator+=(int day)实现:日期+=天数 ,得到一个新的日期

思路很简单就是进位的思想:满了这个月的天数就进到下一个月。

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

这里面的“  +=  ”就是我们自己写的+=函数,也是+=运算符的重载函数。这里加cosnt是为了应付cosnt类型的数据。 

2.4 Date& operator-=(int day)

Date& operator-=(int day):日期-=天数。

实现思路与+=相似,采用退位的方式。这个月的天数不够就借用前一个月的天数。

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

2.5 Date& operator++()

Date& operator++():前置++运算符的重载实现,前置++特点,先++后引用

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

2.6 Date operator++(int)

Date operator++(int):后置++特点先引用后++,为了分清楚前置++还是后置++,祖师爷定义了后置++在运算符重载时会多一个没有任何作用的int 参数(作用知道这个是后置++)

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

     // 后置--   Date operator--(int);      // 前置--    Date& operator--();

大家可以自己实现--的功能,道理一样。不会实现的电疗伺候。

// 后置--
Date Date::operator--(int)
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}
// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

2.7 bool operator < (const Date& d)const

bool operator < (const Date& d)const:比较日期的大小

思路:依次比较 先比较年 再比较月 再比较日 。这里我们使用逆向思维成立的为条件。

// d1 < d2
// <运算符重载
bool Date::operator < (const Date& d)const
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month < d._month)
			return true;
	}
	else if (_month == d._month)
	{
		return _day == d._day;
	}
	return false;
}

 

2.8 bool operator==(const Date& d)const

 bool operator==(const Date& d)const:日期相等

思路还是延续之前的比较大小的。

// ==运算符重载
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 !(*this <= d);
}

// >=运算符重载
bool Date::operator >= (const Date& d)const
{
	return !(*this < d);
}

// <=运算符重载
bool Date::operator <= (const Date& d)const
{
	return *this < d || *this == d;
}
// 
// !=运算符重载
bool Date::operator != (const Date& d)const
{
	return !(*this == d);
}

2.9 int operator-(const Date& d)const

int operator-(const Date& d)const:实现两个日期相减。

思路1:依靠着进位和退位来计算差值。(不能确定相差的月是哪几个月)。

思路2:直接通过计算来达到相同的日期(有人会说这样效率低下,但是我们的cpu一秒跑很快所以不用担心这些效率)

我们这里采用思路2

// 日期-日期 返回天数
int Date::operator-(const Date& d)const
{
	int flag = 1;
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n*flag;
}

这个代码大部分都很普通,点睛之笔在这个flag他防止用小日期-大日期得到正天数的麻烦。 

2.10 ostream& operator<<(ostream& out, const Date& d)

ostream& operator<<(ostream& out, const Date& d):输出流操作符重载

我们没有把这两个函数写道类里面,因为类的成员函数会把第一个参数直接给到this指针,这样不方便我们的正常的写作。所以我们就写到了类外面,但是这样我们就使用不了类里面的私有变量了。有一个解决方案,那就是友元函数的声明在类里面。

类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

friend ostream& operator<<(ostream& out, const Date& d);//友元函数的声明

ostream& operator<<(ostream& out, const Date& d)//写成友源函数就可以访问到类里面的私有变量了
//这里类型改成ostream是方便多次输出
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

这里返回类型写成了 ostream是方便多次输出,因为输出流就是这个类型。 

2.11 istream& operator>>(istream& i, Date& d)

istream& operator>>(istream& i, Date& d): //输入流操作符重载

与上面同理写成友元函数

friend istream& operator>>(istream& in, Date& d);//友元函数的声明

istream& operator>>(istream& in ,Date& d)//这里类型改成istream是方便多次输入
{
	while (1)
	{
		cout << "请输入日期 > :";
		in >> d._year >> d._month >> d._day;
		if (!d.Check())
		{
			cout << "非法日期!";
			d.Print();
			cout << "重新输入日期";
		}
		else
		{
			break;
		}
	}

	return in;
}

三、 完整代码

Date.cpp

Date.cpp
#define _CRT_SECURE_NO_WARNINGS
#include"Date.h"
// 日期+=天数
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= (-day);
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			++_year;
			_month = 1;
		}
	}
	return *this;
}

bool Date::Check()//检查日期是否合法
{
	if (_month < 1 || _month > 12 || _day < 1
		|| _day > Date::GetMonthDay(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

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

// 日期+天数
Date Date::operator+(int day)const
{
	Date tmp = *this;
	tmp += day;
	return tmp;
}

// 日期-天数
Date Date::operator-(int day)const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

// 日期-=天数
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += (-day);
	}
	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}
// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
// 后置++
Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}
// 后置--
Date Date::operator--(int)
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}
// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
// >运算符重载
bool Date::operator>(const Date& d)const
{
	return !(*this <= d);
}
// ==运算符重载
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 !(*this < d);
}

// d1 < d2
// <运算符重载
bool Date::operator < (const Date& d)const
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month < d._month)
			return true;
	}
	else if (_month == d._month)
	{
		return _day == d._day;
	}
	return false;
}

// <=运算符重载
bool Date::operator <= (const Date& d)const
{
	return *this < d || *this == d;
}
// 
// !=运算符重载
bool Date::operator != (const Date& d)const
{
	return !(*this == d);
}
// 
// 日期-日期 返回天数
int Date::operator-(const Date& d)const
{
	int flag = 1;
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n*flag;
}

//void operator<<(ostream& out)//this是当前类的类型。
//{
//	out << _year << "年" << _month << "月" << _day << "日" << endl;
//}

ostream& operator<<(ostream& out, const Date& d)//写成友源函数就可以访问到类里面的私有变量了
//这里类型改成ostream是方便多次输出
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

istream& operator>>(istream& in ,Date& d)//这里类型改成istream是方便多次输入
{
	while (1)
	{
		cout << "请输入日期 > :";
		in >> d._year >> d._month >> d._day;
		if (!d.Check())
		{
			cout << "非法日期!";
			d.Print();
			cout << "重新输入日期";
		}
		else
		{
			break;
		}
	}

	return in;
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS
#include"Date.h"
int main()
{
	/*Date s1(200, 10, 3);
	s1.Print();*/


	/*Date s2(2005, 10, 1);
	s2.Print();*/
	//cout << s1 - s2 << endl;
	//s1 -= 20;
	// s1.Print();测试减法
	//s1 += 20;
	//s1.Print();测试加法
	//Date s2 = ++s1;//测试前置++
	//s2.Print();
	//s1.Print();

	//s1 << cout;//和我们平常写的太不一样,放弃。

	//cout << s2 << s1 << endl;//这样就非常适合我们平常的写作习惯了

	Date d1;
	cin >> d1;

	cout << d1 + 50;

	return 0;
}

 

总结

感谢大家的支持,我会继续努力创造出更好的博客。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值