C++类与对象——日期类的实现

上篇,我们了解了赋值运算符后,现在我们来用赋值运算符来实现一下日期类

在开始之前,我们得完善一下各个赋值运算符:==,<,<=,>=,!=等等

关于上面的赋值运算符,我们只要先写出<,==这两个,其余的按照赋值运算符这个代<,==这两种情况复用就可以。

首先,写一个日期的类框架:

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1);

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	Date(const Date& d)  
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

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

赋值运算符:

一:<

bool Date::operator<(const Date& x)
{
	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;
	}

	return false;
}

 二:==

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

 三:<=

<=是什么情况?是不是就是上面的两种情况合起来?所以我们就可以在上面的基础下,复用起来:

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

四:>

大于:基于上面的基础,是不是就相当于都不符合(等于)上面两种的情况:

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

 五:>=

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

六:!= 

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

 比较简单,就不多说了。

 

一:日期

无论是日期加还是减天数,那么我们都是要先得到每个月的天数的,每个月的天数又是不一样的,那么,我们先实现如何得到每个月的天数吧:

int Date::GetMonthDay(int year, int month)
{
	static int daysArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
                   //月份:     0  1   2   3   4   5   6   7   8   9   10  11  12
	//if (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) && month == 2)  
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}
	else
	{
		return daysArr[month];
	}
}

讲解:

1.我们之前C语言中一般算月份的天数会用switch来实现,但是这个会有点麻烦,所以不妨直接用数组来实现,数组的下标来代表月份,数组的值代表该月份的天数。

2.由于我们的月份是没有0月的说法的,为了更加方便辨别,我们去数组的大小13个,这样子就可以一一对应月份起来了。

各个月份天数:

一三五七八十腊,三十一天永不差。 1,3,5,7,8,10,12 这几月永远31天。2月平年28天,闰年(一般年份能整除4或百年年份能整除400的是闰年,)29天,其他月份30天。 

3.我们又知道,关于闰年还是平年的话,我们的二月份的天数也是不同的,所以我们还要另外考虑闰年平年的二月。(相信大家在C语言时也有了解过闰年平年的判断方法了)。

下面给出闰年的定义:

  1. 普通年份:如果年份能被4整除但不能被100整除,则是闰年。例如,2004年是闰年,而1900年不是闰年。

  2. 世纪年份:如果年份是整百数,它必须能被400整除才是闰年。例如,2000年是闰年,但2100年不是闰年。

4.另外,大家看看

1.if (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) && month == 2)  
2.if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))

1和2的代码,谁的效率更高呢?为什么?

答:2的代码效率更高,因为:我们知道,执行顺序是从左到右的,而2中,一开始就先判断了月份是否是二月,如果不是,它就不用执行判断后面的代码(直接不进入),而1中,它并没有先判断月份,就先判断是不是闰年,这样,即使年份是闰年,但是月份不是2月,也就进不去的,反而浪费了时间来判断,所以说,2的代码效率更高。

 

1)日期+=天数

内容:日期加上天数后的日期是多少?

eg:2025年3月8号 加上50天后的日期是什么呢?

那么,我们先看看按照我们现实生活时怎么计算的呢?

 

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

讲解:

1.为什么这里返回类型是Date&呢?因为它返回的是this指针,不会改变它的值的,所以出了函数作用域,对象还在,所以用引用返回。

比如说:a +=10;每次加完了之后a也会变化的,所以直接返回this指针,即可传引用

2.我们先加起来日期的天数,判断若天数大于该月份的天数,则进入循环,反之不进入。

3.进入循环之后,说明已经超过了该月本来最大的天数了,所以,月份+1,总的天数减去该

月份本来最大的天数,知道小于该月份的最大天数,就说明完成了。

4.月份+1的过程中,当然还要判断月份是否超过了12,超了就到年+1了。

2)日期+天数

这个和上面的那个有什么区别呢?

我们用例子来形象说明:

int a=5;

1.a+=10;

2.a+10;

我们从上面代码分析:当1时,我们的a会不会变?a会变成a=15吧

而2时,a的值会变吗?不会的,仍然是a=5。

所以说,如果我们日期+天数还是用上面的代码来实现的话,是不是就不行了。

由于我们写出了上面+=的了,所以这里可以直接复用 

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

}

1.因为*this指针不能改变,所以创建一个临时变量的日期类

2.我们这里,返回的是temp出了作用域就并不存在了,所以不能使用& 传引用。

下面看看这两种那种更优?为什么呢?

第一种更优。原因:因为上面改变的(临时)变量少,只有2次 ,下面有4次。所以说我们最好用上面的解法。

3)日期-=天数

同日期+=天数,现在我们来看一下现实生活中我们是怎么计算的:

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}

	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}

		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

1.检查月份是否小于0,那么年--;

2.具体过程的话,跟我画的上面的图一样的思路,可以看看上面的图。 

 4)日期-天数

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

 这里原理跟日期+=天数和日期+天数差不多的,这里也不过多讲解了。
 

5)前置++和后置++

我们知道:

前置++:是先++,后使用

后置++:先使用,后++。

由于为了区别日期类的++,C++中做了两者的区分:

 没有增加这个int参数的是前置++,加了的是后置++,

注意:增加这个int参数不是为了接收具体的值,仅仅是占位,跟前置++构成重载,所以赋不赋值都无所谓。反正我们又不具体使用它。

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

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

6)前置--和后置--

跟前置++后置++一样。

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

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

7)日期-日期

我们的日期+日期是没有什么价值的,但是日期-日期,我们可以看出这两个日期区间已经过了多少天的价值。比如:现在距离你出生那天已经过了多少天了,人类的寿命大概又多少天。

目的:返回天数

思路:

比如:2025-3-8     2000.1.1为例子

如果我们以日减日,月-月,年-年的方法一步一步地减下去,这样是不是就特别麻烦。

所以这里我们不妨使用

将2025-3-8 先变成2025-1-1

这样算出它们相距的差:年:25年 ,

接着再去减去它们的月日:3月8----1月1之间的天数。

int Date::operator-(const Date& d) const
{
	Date max = *this;
	Date min = d;
	int flag = 1;

	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n * flag;
}

上面代码,单独看的话有点乱,所以我在下面给出了它运行调用时的顺序,可以方便大家理解(我开始时看不懂,画了图后就懂了)。 

 

好了,本次分享就结束了。

最后来到了我们的鸡汤部分:

 阻碍我们前行的障碍莫过于长久地坚持。一份永恒的耐心,是多少人梦寐以求的精髓,可这就体现在平常的生活,只需我们拾起一片真心,逐渐积累罢了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值