首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >日期类 Date 的实现与详细解析

日期类 Date 的实现与详细解析

作者头像
君辣堡
发布2025-12-20 09:05:54
发布2025-12-20 09:05:54
1640
举报

基于我们学过的类的默认成员函数,接下来这一篇,我将解释如何实现日期类 Date :

// 函数默认在.cpp文件定义,所以需要指明类域。

   我就默认是头文件分离的方式了。接下来我将展示日期类的函数声明代码:

代码语言:javascript
复制
#include<iostream>
#include<assert.h>
using namespace std;

class Date
{
public:
	void Print();
	// 获取某年某月的天数
	int GetMonthDay(int year, int month);
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	// 拷贝构造函数
    // d2(d1)
	Date(const Date& d);
	// 赋值运算符重载
    // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);
	// 析构函数
	~Date();
	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day);
	// 日期-天数
	Date operator-(int day);
	// 日期-=天数
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();
	// >运算符重载
	bool operator>(const Date& d);
	// ==运算符重载
	bool operator==(const Date& d);
	// >=运算符重载
	bool operator >= (const Date& d);
	// <运算符重载
	bool operator < (const Date& d);
	// <=运算符重载
	bool operator <= (const Date& d);
	// !=运算符重载
	bool operator != (const Date& d);
	// 日期-日期 返回天数
	int operator-(const Date& d);
private:
	int _year;
	int _month;	
	int _day;
};

如图,函数有很多,其中,不变的就3个内置类型:_year,_month,_day ,我们将围绕这三个展开函数:

1.Print 函数

此函数的目的就是打印日期,那么只需要调用cout就行:

代码语言:javascript
复制
void Date::Print ()
{
    cout << _year << "-" << _month << "-" << _day << endl;
}

所以也是很简单就拿下了。中间的分隔符我们用“-”表达,也可以换成其他的。

2.GetMonthDay函数

字面意思,这是获取某月天数的问题。既然是获取天数,那必然涉及到判断闰年的问题,并且返回

值是int,说明要返回这个月的天数。而这个很简单,C语言就接触过这种题目,我们只需要把12个

月份的日期写出来,找出2月份判断一下是否闰年,然后单独改变2月天数,然后返回就行。在这里

我直接展示代码:

代码语言:javascript
复制
	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		//static,不用每次都重新在栈帧中创建,方便点
		static int monthDayArray[13] = { -1, 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 monthDayArray[month];
		}
	}

这里用了很巧妙的方法,创建了一个数组,长度为13的数组,把索引0用-1(无意义的数字)代

替,剩下的索引1到12下标刚好与月数对应。然后还在数组前加了static,将数组变为静态,这样

就不用每次都重新在栈帧中创建删除,更方便,代码的可读性和效率都更高了。同时,用assert断

言判断了月份的合法性,使代码更完善。

3.Date全缺省构造函数

只需要注意若定义分离在.cpp文件,不能重复声明缺省值 ,也就是说,在.h文件中声明并指定了缺

省值后,在.cpp文件定义就不需要写。然后,构造函数的目的是在对象实例化时给对象初始化,那

么就是很简单地对年月日赋值,最后别忘了构造函数的特点,函数名与类类型相同:

代码语言:javascript
复制
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

4.拷贝构造函数

拷贝构造函数讲过,对成员变量全都是内置类型, 比如日期类Date 并且没有申请资源的,编译器

默认生成的拷贝构造就够用,所以不需要显式实现。它的逻辑就是对内置类型浅拷贝,也就是赋

,所以和上面类似,对 对象中的年月日进行拷贝赋值就行:

代码语言:javascript
复制
Date::Date(const Date& d)
{
    _year=d.year;
    _month=d._month;
    _day=d._day;
}

5.赋值运算符重载函数

与上面写的拷贝构造非常类似,经常有人搞混。需要注意,其返回值是 当前类类型的引用,也就

是Date&,然后就是对 对象的成员年月日 进行赋值:

代码语言:javascript
复制
Date& Date::operator=(const Date& d)
{
	if (this != &d)//检查地址,相同则不需要赋值
	{
		_year = d._year;
		_month = d._month;		
		_day = d._day;
	}
	return *this;
}

如图。需要注意,因为赋值运算符重载针对的是两个已经存在的对象,所以他们地址可能相同,此

处最好加上一个检查自身赋值的 if 条件语句,进一步提高了代码的效率和健壮性。

6.析构函数

Date类的成员变量都没有申请资源,所以不需要显式写。要写就是空着,比如:

代码语言:javascript
复制
Date::~Date()
{
    
}

不过能不写就建议不写。因为写了没用的代码会导致带代码冗余。

7.日期+=天数

日期+=天数,那最终返回的是Date类型,所以需要用引用返回,因为其出了函数作用域还存在。

参数只有一个int day是因为第一个参数为this指针。那么该怎么写这个函数?我的思路是:直接进

行+=操作:_day+=day;  ,如果加完后天数大于当月天数,那就使月数++,并且减去当月的最大天

数。若月等于13月,则年数++,月数=1;考虑到加的天数可能很多,那就需要循环这个过程,所

以使用while循环:

while(_day>GetMonthDay(_year,_month))最后日期就求出来了。下面是代码:

代码语言:javascript
复制
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;
}

图中增加了如果输入负数天数的情况,此时就转化为*this -= -day,把加负天数转化为减正天数,这

也是复用了-=的函数,提高了代码效率。-= 的实现将在后面解释。

8.日期+天数

这个函数的实现逻辑与 日期+=天数 很像,区别就是日期+=天数会 改变被加数(日期)的值,而

日期+天数不改变原日期,只是得出一个新的值,被加数(日期)并未改变。

那么我们可以直接创建一个临时对象 tmp 对 *this 进行 浅拷贝,然后复用日期+=日期的函数,最

返回tmp,而不返回*this 这样做到了不修改原日期,只得出结果。  代码如下:

代码语言:javascript
复制
Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}

需要说明,因为返回的是临时对象tmp,其作用域只在函数内,所以不能使用引用返回

9.日期-=天数

日期-=天数,会修改原对象,则最后返回*this指针。对于这个函数,我的思路是:先让他们相减,

如果天数大于0,说明月数没变,当月剩余天数比要减的大。如果小于0或者等于0,就需要重复+=

中月数和年数改变的操作,并且可能重复多次,所以用while循环:while(_day<=0) ,   然后就能

得出答案,代码如下:

代码语言:javascript
复制
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;
}

同样,如果要减去的天数小于0,则把 减负天数 转换成 加正天数 ,这样复用了+=函数,提高了效

率。+=函数的解释在上面,这两个函数相辅相成。

10.日期-天数

一样,可以复用日期-=天数,同时也需要注意,返回对象应是未经修改的原日期,那么直接同样创

建临时对象tmp对*this进行浅拷贝,最后返回tmp,代码:

代码语言:javascript
复制
Date Date::operator-(int day)
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}

因为返回的是临时对象tmp,其作用域只在函数内,所以不能使用引用返回

11.前置++

前置++,很简单,就是让天数加一天,可以直接复用+=,而且返回运算后的结果,也就是修改后

的日期

代码语言:javascript
复制
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

12.后置++

这个和前置++一样,让天数加一天,但是不完全一样,因为是后置++,返回的应该是运算前的结

果,也就是原日期的值,并且原日期是被修改了的

代码语言:javascript
复制
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

这里我们继续创建临时对象tmp,接收原日期的值然后使原日期*this被改变,但是返回原日期

。参数中加了一个无意义的int,只是为了区分前置++

13.前置--

和前后置++逻辑一样

代码语言:javascript
复制
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

14.后置--

和前后置++逻辑一样

代码语言:javascript
复制
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

因为返回的是临时对象tmp,其作用域只在函数内,所以不能使用引用返回

15.operator>

运算符重载函数,重载大于号,那只需要在其中依次比较年月日大小即可,若年相同,比月,月相

同比日,有一个大就返回true,到最后了如果都一样就返回false,代码如下:

代码语言:javascript
复制
bool Date::operator>(const Date& d)
{
	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month > d._month)
		{
			return true;
		}
		else if (_month == d._month)
		{
			if (_day > d._day)
			{
				return true;
			}
		}
	}
	return false;
}

16.operator==

运算符重载函数,重载了等于  ==  ,那么直接依次比较年月日,中间用并列符号 && ,直接返回

这串表达式即可,代码:

代码语言:javascript
复制
bool Date::operator==(const Date& d)
{
	return _year == d._year && _month == d._month && _day == d._day;
}

17.operator<=

小于等于,那就是 < 的反面,那最简单的办法就是复用 > ,利用逻辑非(!)表达:

代码语言:javascript
复制
bool Date::operator <= (const Date& d)
{
	return !(*this > d);
}

18.operator>=

代码语言:javascript
复制
bool Date::operator >= (const Date& d)
{
	return (*this > d) || (*this == d);
}

19.operator<

代码语言:javascript
复制
bool Date::operator < (const Date& d)
{
	return (*this >= d);

20.operator!=

代码语言:javascript
复制
bool Date::operator != (const Date& d)
{
	return  !(*this == d);
}

以上的逻辑类似,所以不作过多解释。

21.operator-

日期-日期 ,思路是 : 设置两个日期,一个max,一个min,用if比较(max>min)不是则反过

来。小的日期++,去追大的日期,期间day++,直到min大于max,循环条件while(min<max),最

后返回计数器day,然后flag代表+-代码如下:

代码语言:javascript
复制
int Date::operator-(const Date& d)
{
	int flag = 1;
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		min = *this;
		max = d;
        flag=-1;
	}
    int day=0;
	while (min < max)
	{
		++min;
		++day;
	}
	return day*flag;
}
至此,日期类Date 完成。如果有错误的地方请大佬在评论区指出,谢谢大家!请多多点赞支持我!
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.Print 函数
  • 2.GetMonthDay函数
  • 3.Date全缺省构造函数
  • 4.拷贝构造函数
  • 5.赋值运算符重载函数
  • 6.析构函数
  • 7.日期+=天数
  • 8.日期+天数
  • 9.日期-=天数
  • 10.日期-天数
  • 11.前置++
  • 12.后置++
  • 13.前置--
  • 14.后置--
  • 15.operator>
  • 16.operator==
  • 17.operator<=
  • 18.operator>=
  • 19.operator<
  • 20.operator!=
  • 21.operator-
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档