【CPP】手把手教会日期类,日期类实现思路,详细思路

今天简单来说一下日期类的实现,算是一个小的练习吧。

1.日期类是什么?

日期是表示时间的一种计量数字。比如我们常说公历农历。

在这里我分享的这个日期类是大大进行简化的,比如时间精度只精确到天,有效范围是0年0月0日之后…事实上,日期是非常复杂的,比如精度要精确到秒,还有大量特殊的日期,是大概1600年之后每年才比较正常,之前由于历史原因,有各种人为添加日子的情况…再加上润年的考虑…总之就是很麻烦。

2.日期类框架的构建

我们是用CPP语言来写一个简单的日期类的。那我们就按照CPP的思想先描述后组织进行依次实现。

我们用一个类来描述对应的日期,把日期看作一个对象来进行实现。

// Date.h
class Date
{
private:
	int _day;
	int _month;
	int _year;
}

好的,我们就简单的写了一个类来描述日期这一对象,然后我们再进行组织完善。

3.构造函数重写

虽说自定义类型编译器会默认给我们生成一个默认构造函数,但是显然不能满足我们的需求。
在重写构造函数的时候,我们需要考虑构造函数构造出来的日期对象是否合法的一个问题。

// Date.h
class Date
{
private:
	int _day;
	int _month;
	int _year;
public:
	Date(int year = 1, int month = 1, int day = 1);
}

这里实现一个全缺省的构造函数,不用写多个重载构造了,这样写比较方便。
然后我们在Date.cpp的文件里实现我们的重写的构造函数:先不要被劝退,从下往上看很简单,只是稍微长一点而已。下面是Date.cpp内容

// Date.cpp
bool CheckLeapYear(int year, int month)
{
	if ((!(year % 4) && (year % 100)) || !(year % 400)) return true;
	else return false;
}

int GetMonthDays(int year, int month)
{
	assert(month >= 1 && month <= 12);
	static int Months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	if (month == 2 && CheckLeapYear(year, month)) return Months[month] + 1;
	else return Months[month];
}

bool Date::CheckInvalid()
{
	if (_year < 0 || _month > 12 || _month < 1 || _day < 0 || _day > GetMonthDays(_year, _month)) return false;
	else return true;
}

Date::Date(int year, int month, int day)
	:_year(year),_month(month),_day(day)
{
	if (!CheckInvalid()) std::cout << "error reprint" << std::endl;
}

然后我又考虑到,我们每次创建一个日期对象,都需要调用构造函数,那么每次都要调用CheckInvalid()和GetMonthDays()函数,也就是说这俩函数比较短小且被频繁调用,我干脆直接把他实现成内联函数得了。

然后就可以实现为下面这个样子:

// Date.cpp
#include"Date.h"

bool Date::CheckInvalid()
{
	if (_year < 0 || _month > 12 || _month < 1 || _day < 0 || _day > GetMonthDays(_year, _month)) return false;
	else return true;
}

Date::Date(int year, int month, int day)
	:_year(year),_month(month),_day(day)
{
	if (!CheckInvalid()) std::cout << "error reprint" << std::endl;
}
// Date.h
class Date
{
private:
	int _day;
	int _month;
	int _year;
public:
	Date(int year = 1, int month = 1, int day = 1); //简单的缺省构造函数 Date() --> CheckInvalid() --> CheckLeapYear --> GetMonthDays
	bool CheckInvalid();
	inline bool CheckLeapYear(int year, int month)
	{
		if ((!(year % 4) && (year % 100)) || !(year % 400)) return true;
		else return false;
	}
	inline int GetMonthDays(int year, int month)
	{
		assert(month >= 1 && month <= 12);
		static int Months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

		if (month == 2 && CheckLeapYear(year, month)) return Months[month] + 1;
		else return Months[month];
	}
}

做好了上面这些,日期类的构造函数算是重写完了。
我们再写一个打印日期类的函数,方便我们以后测试结果。

4.打印函数

不知道大家写代码什么习惯,因为我现在是初学者,所以写一些代码都是比较基础的,所以很多时候直接开始写一个打印函数比较容易观察现象,定位错误。

void Date::DatePrint() const
{
	std::cout << this->_year << "/" << this->_month << "/" << this->_day << std::endl;
}

注意哈,写完了打印函数要记得把这个函数声明到Date.h中去。

5.常见的Date判断函数

我们根据生活常识可知,日期类是可以进行比较大小的,比如说2024.7.25就是比2024.7.24大呀,又或者说2024.7.25与2024.7.24不是同一天(显然这是废话)…所以我们写的Date也要支持这些比较操作。
大概有下面声明的这几个比较判断操作:

// Date.h
class Date
{
private:
	int _day;
	int _month;
	int _year;
public:
	Date(int year = 1, int month = 1, int day = 1); //简单的缺省构造函数 Date() --> CheckInvalid() --> CheckLeapYear --> GetMonthDays
	bool CheckInvalid();
	inline bool CheckLeapYear(int year, int month)
	{
		if ((!(year % 4) && (year % 100)) || !(year % 400)) return true;
		else return false;
	}
	inline int GetMonthDays(int year, int month)
	{
		assert(month >= 1 && month <= 12);
		static int Months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

		if (month == 2 && CheckLeapYear(year, month)) return Months[month] + 1;
		else return Months[month];
	}

	void DatePrint() const; // 打印Date类对象信息

	// 一些常见的判断操作
	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;

然后我们着手实现的时候,因为这里有六个判断操作,并且他们之间有特定的关系,比如说小于等价于大于等于取反不等于等价于等于取反,这个地方就可以实现两个判断操作,剩下的一顿复用就行。

#include"Date.h"

bool Date::CheckInvalid()
{
	if (_year < 0 || _month > 12 || _month < 1 || _day < 0 || _day > GetMonthDays(_year, _month)) return false;
	else return true;
}

Date::Date(int year, int month, int day)
	:_year(year),_month(month),_day(day)
{
	if (!CheckInvalid()) std::cout << "error reprint" << std::endl;
}

void Date::DatePrint() const
{
	std::cout << this->_year << "/" << this->_month << "/" << this->_day << std::endl;
}

bool Date::operator<(const Date& d) const
{
	if (this->_year < d._year) return true;
	else if(this->_year == d._year)
	{
		if (this->_month < d._month) return true;
		else if (this->_month == d._month && this->_day < d._day) return true;
	}

	return false;
}

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


bool Date::operator<=(const Date& d) const
{
	if (*this < d || *this == d) return true;
	else return false;
}

bool Date::operator>(const Date& d) const
{
	if (!(*this <= d)) return true;
	else return false;
}

bool Date::operator>=(const Date& d) const
{
	if (!(*this < d)) return true;
	else return false;
}

bool Date::operator!=(const Date& d) const
{
	if (!(*this == d)) return true;
	else return false;
}

上面这六个判断函数就是典型的代码复用例子,以后写代码可以多注意这种代码复用技巧,比较省力是吧。

我们写完了日期之间的比较判断,其实日期也是可以进行运算的。

6.日期类的运算

不知道大家注意到没有,日期是可以进行运算的。比如今天是2024年7月25日,那么在今天的基础上减一操作,也就是前一天是2024.7.14,当然也可以加上30天,看看三十天后是几月几号。我们也可以拿到两个日期来算他们之间差多少天…当然需要注意的是有些日期运算是没有意义的,比如一个日期+另一个日期是没有意义的,我们也就不必实现没有意义的运算。

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

class Date
{
private:
	int _day;
	int _month;
	int _year;
public:
	Date(int year = 1, int month = 1, int day = 1); //简单的缺省构造函数 Date() --> CheckInvalid() --> CheckLeapYear --> GetMonthDays
	bool CheckInvalid();
	inline bool CheckLeapYear(int year, int month)
	{
		if ((!(year % 4) && (year % 100)) || !(year % 400)) return true;
		else return false;
	}
	inline int GetMonthDays(int year, int month)
	{
		assert(month >= 1 && month <= 12);
		static int Months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

		if (month == 2 && CheckLeapYear(year, month)) return Months[month] + 1;
		else return Months[month];
	}

	void DatePrint() const; // 打印Date类对象信息

	// 一些常见的判断操作
	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+=(const int day);
	Date operator+(const int day) const;
	Date& operator++(); // 前置++
	Date operator++(int); // 后置++
	int operator-(Date& d);

实现一下:

Date& Date::operator+=(const int day)
{
	this->_day += day;

	while (_day > GetMonthDays(this->_year, this->_month))
	{
		this->_day -= GetMonthDays(this->_year, this->_month);
		this->_month++;
		if (this->_month > 12)
		{
			this->_month = 1;
			this->_year++;
		}
	}

	return *this;
}

Date Date::operator+(const int day) const
{
	Date temp = *this; // 拷贝构造
	temp += day;

	return temp;
}

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

	return *this;
}

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

	return temp;
}

int Date::operator-(Date& d)
{
	int sub = 0;

	Date max, min;
	if (*this > d)
	{
		max = *this;
		min = d;
	}
	else
	{
		max = d;
		min = *this;
	}

	while (max != min)
	{
		min++;
		sub++;
	}

	return sub;
}

处理完了日期类的运算,基本最难的也就过去了,还有个比较重要的流插入和流提取去重写,基本日期类就写完了。

7.流插入、流提取

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

class Date
{
private:
	int _day;
	int _month;
	int _year;
public:
	Date(int year = 1, int month = 1, int day = 1); //简单的缺省构造函数 Date() --> CheckInvalid() --> CheckLeapYear --> GetMonthDays
	bool CheckInvalid();
	inline bool CheckLeapYear(int year, int month)
	{
		if ((!(year % 4) && (year % 100)) || !(year % 400)) return true;
		else return false;
	}
	inline int GetMonthDays(int year, int month)
	{
		assert(month >= 1 && month <= 12);
		static int Months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

		if (month == 2 && CheckLeapYear(year, month)) return Months[month] + 1;
		else return Months[month];
	}

	void DatePrint() const; // 打印Date类对象信息

	// 一些常见的判断操作
	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+=(const int day);
	Date operator+(const int day) const;
	Date& operator++(); // 前置++
	Date operator++(int); // 后置++
	int operator-(Date& d);

	// 流插入和流提取
	friend std::ostream& operator<<(std::ostream& out, const Date& d);
	friend std::istream& operator>>(std::istream& in, Date& d);
};

std::ostream& operator<<(std::ostream& out, const Date& d);
std::istream& operator>>(std::istream& in, Date& d);
std::ostream& operator<<(std::ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << std::endl;

	return out;
}

std::istream& operator>>(std::istream& in, Date& d)
{
	while (true)
	{
		in >> d._year >> d._month >> d._day;
		if (!d.CheckInvalid())
		{
			std::cout << "error, refail" << std::endl;
			continue;
		}
		else
		{
			break;
		}
	}

	return in;
}

这个流插入和流提取用到了友元函数、并且与其他的函数不同,其他函数是声明在了Date类内,而流插入提取在类外。
这个主要是因为流插入提取如果声明在类内,第一个参数就一定是隐藏this指针,到时候我们在外面调用流插入的时候写法会很离谱。这里就不多说了。详见下图:
在这里插入图片描述
好了,终于说完了实现Date类的大体思路了,感觉我只是说了一下大体的实现思路,每个函数具体怎么去实现,我想代码是最具体的,当然有些地方可能有疑问,问什么这么做为什么这样处理,先思考,不明白可以评论区里问。

下面把全部代码放下面,有需要可以看看全部代码。

8.全部代码

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

class Date
{
private:
	int _day;
	int _month;
	int _year;
public:
	Date(int year = 1, int month = 1, int day = 1); //简单的缺省构造函数 Date() --> CheckInvalid() --> CheckLeapYear --> GetMonthDays
	bool CheckInvalid();
	inline bool CheckLeapYear(int year, int month)
	{
		if ((!(year % 4) && (year % 100)) || !(year % 400)) return true;
		else return false;
	}
	inline int GetMonthDays(int year, int month)
	{
		assert(month >= 1 && month <= 12);
		static int Months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

		if (month == 2 && CheckLeapYear(year, month)) return Months[month] + 1;
		else return Months[month];
	}

	void DatePrint() const; // 打印Date类对象信息

	// 一些常见的判断操作
	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+=(const int day);
	Date operator+(const int day) const;
	Date& operator++(); // 前置++
	Date operator++(int); // 后置++
	int operator-(Date& d);

	// 流插入和流提取
	friend std::ostream& operator<<(std::ostream& out, const Date& d);
	friend std::istream& operator>>(std::istream& in, Date& d);
};

std::ostream& operator<<(std::ostream& out, const Date& d);
std::istream& operator>>(std::istream& in, Date& d);
// Date.cpp
#include"Date.h"

bool Date::CheckInvalid()
{
	if (_year < 0 || _month > 12 || _month < 1 || _day < 0 || _day > GetMonthDays(_year, _month)) return false;
	else return true;
}

Date::Date(int year, int month, int day)
	:_year(year),_month(month),_day(day)
{
	if (!CheckInvalid()) std::cout << "error reprint" << std::endl;
}

void Date::DatePrint() const
{
	std::cout << this->_year << "/" << this->_month << "/" << this->_day << std::endl;
}

bool Date::operator<(const Date& d) const
{
	if (this->_year < d._year) return true;
	else if(this->_year == d._year)
	{
		if (this->_month < d._month) return true;
		else if (this->_month == d._month && this->_day < d._day) return true;
	}

	return false;
}

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


bool Date::operator<=(const Date& d) const
{
	if (*this < d || *this == d) return true;
	else return false;
}

bool Date::operator>(const Date& d) const
{
	if (!(*this <= d)) return true;
	else return false;
}

bool Date::operator>=(const Date& d) const
{
	if (!(*this < d)) return true;
	else return false;
}

bool Date::operator!=(const Date& d) const
{
	if (!(*this == d)) return true;
	else return false;
}

Date& Date::operator+=(const int day)
{
	this->_day += day;

	while (_day > GetMonthDays(this->_year, this->_month))
	{
		this->_day -= GetMonthDays(this->_year, this->_month);
		this->_month++;
		if (this->_month > 12)
		{
			this->_month = 1;
			this->_year++;
		}
	}

	return *this;
}

Date Date::operator+(const int day) const
{
	Date temp = *this; // 拷贝构造
	temp += day;

	return temp;
}

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

	return *this;
}

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

	return temp;
}

int Date::operator-(Date& d)
{
	int sub = 0;

	Date max, min;
	if (*this > d)
	{
		max = *this;
		min = d;
	}
	else
	{
		max = d;
		min = *this;
	}

	while (max != min)
	{
		min++;
		sub++;
	}

	return sub;
}

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

	return out;
}

std::istream& operator>>(std::istream& in, Date& d)
{
	while (true)
	{
		in >> d._year >> d._month >> d._day;
		if (!d.CheckInvalid())
		{
			std::cout << "error, refail" << std::endl;
			continue;
		}
		else
		{
			break;
		}
	}

	return in;
}

EOF

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值