【C++程序员的自我修炼】日期类Date的实现

山河日月镌刻璀璨初心

八载春秋写就举世华章


目录

 日期类Date的实现

构造函数 

拷贝构造函数

获取月份天数的函数

 日期类的检查

 日期类的打印

运算符重载日期类的比较 

运算符重载>

运算符重载==

运算符的复用

日期加天数

日期减天数

​编辑 运算符重载+

 运算符重载-

 日期类的前置++

 日期类的后置++

日期类的前置--

日期类的后置--

日期减日期

整体代码的实现


契子✨ 

我们学了那么久的 C++ 类与对象,是时候写个小项目练练手了~

先提前总结一下今天要用到的知识点(日期类Date 最基本的东西):

私有成员,构造函数,拷贝构造函数,析构函数(编译器默认生成),赋值运算符重载


 日期类Date的实现

首先登场的就是我们日期类的成员变量

//私有成员变量:
private:
	int _year;
	int _month;
	int _day;

构造函数 

//构造函数
Date::Date(int year, int month, int day)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}

拷贝构造函数

//拷贝构造函数
Date::Date(const Date& d)
{
	this->_year = d._year;
	this->_month = d._month;
	this->_day = d._day;
}

获取月份天数的函数

<1>因为这个函数后面要反复调用,所以为了节省空间我们最好写成内联的形式

在C++中放在 public 内的就是内联

<2>如果 MonthDayArray 数组没有转化成静态,也就是每调用一次都要进行空间开辟和释放

效率不高,所以我们加 static 进行修饰转换成静态变量

int GetMonthDay(int year, int month)
{
	static int MonthDayArray[13] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	if (this->_month == 2 && ((this->_year % 4 == 0 && this->_year % 100 != 0) || (this->_year % 400 == 0)))
	{
		return 29;
	}
	else
	{
		return MonthDayArray[this->_month];
	}
}

 日期类的检查

bool Date::CheckDate()
{
	if (this->_month < 1 || this->_month>12 || this->_day<0 || this->_day>GetMonthDay(this->_year, this->_month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

 日期类的打印

void Date::Print()
{
	cout << this->_year << " 年 " << this->_month << " 月 " << this->_day << " 日 " << endl;
	if (!CheckDate())
	{
		cout << "非法日期!" << endl;
	}
}

运算符重载日期类的比较 

运算符重载>

bool Date::operator>(const Date& d)
{
	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)
				{
					return this->_day > d._day;
				}
			}
		}
	}
	return false;
}

写好了我们就来测试一下,最好写一点就测一点(不要写代码两分钟,改错两小时)

void Test()
{
	Date d1(2024, 4, 15);
	Date d2(2024, 5, 1);
	if (d1 > d2)
	{
		cout << "d1>d2" << endl;
	}
	else
	{
		cout << "d1<d2" << endl;
	}
	system("pause");
}

事实证明我们的程序是没有任何问题的

运算符重载==

bool Date::operator==(const Date& d)
{
	return this->_year == d._year && this->_month == d._month && this->_day == d._day;
}
void Test()
{
	Date d1(2024, 4, 15);
	Date d2(2024, 5, 1);
	Date d3(2024, 5, 1);
	if (d1 == d2)
	{
		cout << "d1 == d2" << endl;
	}
	else
	{
		cout << "d1 != d2" << endl;
	}
	if (d2 == d3)
	{
		cout << "d2 == d3" << endl;
	}
	else
	{
		cout << "d2 != d3" << endl;
	}
	system("pause");
}

写完 > 和 == 的运算符我们写其他的运算符重载就可以直接复用啦

运算符的复用

bool Date::operator>=(const Date& d)
{
	return (*this > d) || (*this == d);
}

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

bool Date::operator<=(const Date& d)
{
	return !(*this > d) || (*this == d);
}

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

我在这里就不一一进行测试了

日期加天数

<1>首先用当前的天数加上跨越的天数
<2>如果大于当月的最大天数则进入循环进行 消日增月
<3>如果月份超过了 12 则 消月增年
<4>当天数合法则退出循环并返回 *this 
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}
	this->_day += day;
	while (this->_day > GetMonthDay(this->_year, this->_month))
	{
		this->_day -= GetMonthDay(this->_year, this->_month);
		++this->_month;
		if (this->_month == 13)
		{
			++this->_year;
			this->_month = 1;
		}
	}
	return *this;
}

代码测试 -- 网上做好的日期计算器(来看看我们写的是否相符)

void Test()
{
	Date d1(2024, 4, 16);
	d1.Print();
	d1 += 100;
	d1.Print();
	system("pause");
}

事实证明我们的程序是没有任何问题的

我们再来测试一个:

日期减天数

<1>首先用当前的天数减去跨越的天数
<2>如果大于或等于 0 则进入循环进行 消月增日
<3>如果月份不够减,就 消年增月
<4>当天数合法则退出循环并返回 *this 
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}
	this->_day -= day;
	while (_day <= 0)
	{
		--this->_month;
		if (this->_month == 0)
		{
			this->_month = 12;
			--this->_year;
		}
		this->_day += GetMonthDay(this->_year, this->_month);
	}
	return *this;
}

这个和加天数类似,就不进行讲解了

注意:因为总有一些人会在加天数中写负值,在减天数中写正值,所以我们要一开始要判断

 运算符重载+

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

我们这里需要使用拷贝构造,我们要返回的是加后的值,但是并不希望当前日期变化

所以我们使用拷贝函数将当前日期拷贝一份进行加的操作

注意:Date tmp = *thisDate tmp(*this) 是等价的,都是拷贝构造

注意:

运算符重载+,内部创建tmp拷贝构造,值返回拷贝构造(传值调用),2 次调用拷贝构造

日期减天数+=,内部没有拷贝构造

所以综上还是写+=调用拷贝构造的次数少,效率更高

 运算符重载-

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

 日期类的前置++

this 指向的对象函数结束后不会销毁,故以引用方式返回提高效率

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

 日期类的后置++

注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将 this 保存一份

而 tmp 是临时对象,因此只能以值的方式返回,不能返回引用

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

因为前置和后置的命名会冲突,所以 C++ 将 后置++ 的参数设为 int 进行区分

但调用函数时该参数不用传递(参数变量可以不写),编译器自动传递

日期类的前置--

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

日期类的后置--

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

日期减日期

日期减日期返回的是天数,所以我们采用的方法很简单就是用计数器去记录两者相差的天数

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

代码测试:

写一个大家最关心的问题~

void Test()
{
	Date d1(2024, 4, 16);
	Date d2(2024, 5, 1);
	cout << "距离五一放假还有 " << d2 - d1 << " 天" << endl;
	system("pause");
}

再来测试一个:

整体代码的实现

Date.h⭐ 

#include<iostream>
#include<assert.h>
using namespace std;

class Date
{
public:
	Date(int year = 2024, int month = 5, int day = 1);
	Date(const Date& d);
	int GetMonthDay(int year, int month)
	{
		static int MonthDayArray[13] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		if (this->_month == 2 && ((this->_year % 4 == 0 && this->_year % 100 != 0) || (this->_year % 400 == 0)))
		{
			return 29;
		}
		else
		{
			return MonthDayArray[this->_month];
		}
	}
	//判断日期是否正确
	bool CheckDate();
	//打印日期
	void Print();
	//运算符重载
	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)const;
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();
	//计算两个日期之差
	int operator-(const Date& d)const;
private:
	int _year;
	int _month;
	int _day;
};

Date.cpp⭐ 

#include"Date.h"

//构造函数
Date::Date(int year, int month, int day)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}

//拷贝构造函数
Date::Date(const Date& d)
{
	this->_year = d._year;
	this->_month = d._month;
	this->_day = d._day;
}

//判断日期是否正确
bool Date::CheckDate()
{
	if (this->_month < 1 || this->_month>12 || this->_day<0 || this->_day>GetMonthDay(this->_year, this->_month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

//打印日期
void Date::Print() 
{
	cout << this->_year << " 年 " << this->_month << " 月 " << this->_day << " 日 " << endl;
	if (!CheckDate())
	{
		cout << "非法日期!" << 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)
				{
					return this->_day > d._day;
				}
			}
		}
	}
	return false;
}

bool Date::operator==(const Date& d)const
{
	return this->_year == d._year && this->_month == d._month && this->_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) || (*this == d);
}

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

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

Date Date::operator+(int day)const
{
	Date tmp = *this;
	tmp += day;
	return tmp;
}

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

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

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

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

Test.cpp⭐ 

#include"Date.h"

void Test()
{
	Date d1(2024, 4, 16);
	Date d2(2024, 5, 1);
	cout << "距离五一放假还有 " << d2 - d1 << " 天" << endl;
	system("pause");
}

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

 🌤️注意:我上面有些函数加了const修饰,限制了隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改


举个栗子~

我们知道类的成员函数都有一个 隐藏的 this 指针

bool Date::operator>(const Date& d) const

按语法可以写成这个

bool Date::operator>(Date *this,const Date& d) const

等价于下面这个式子

bool Date::operator>(const Date *this,const Date& d) 

我们发现加了 const 限制了成员函数的 this 指针:

表明在该成员函数中不能对类的任何成员进行修改,起到一定的代码安全维护性

 


先介绍到这里啦~

有不对的地方请指出💞

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烟雨长虹,孤鹜齐飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值