上篇,我们了解了赋值运算符后,现在我们来用赋值运算符来实现一下日期类
在开始之前,我们得完善一下各个赋值运算符:==,<,<=,>=,!=等等
关于上面的赋值运算符,我们只要先写出<,==这两个,其余的按照赋值运算符这个代<,==这两种情况复用就可以。
首先,写一个日期的类框架:
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语言时也有了解过闰年平年的判断方法了)。
下面给出闰年的定义:
普通年份:如果年份能被4整除但不能被100整除,则是闰年。例如,2004年是闰年,而1900年不是闰年。
世纪年份:如果年份是整百数,它必须能被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;
}
上面代码,单独看的话有点乱,所以我在下面给出了它运行调用时的顺序,可以方便大家理解(我开始时看不懂,画了图后就懂了)。
好了,本次分享就结束了。
最后来到了我们的鸡汤部分:
阻碍我们前行的障碍莫过于长久地坚持。一份永恒的耐心,是多少人梦寐以求的精髓,可这就体现在平常的生活,只需我们拾起一片真心,逐渐积累罢了。