用简单的日期类巩固C++类与对象基本知识
之前我们已经学习了C++中关于类和对象的一些知识,但是我们还没有具体应用这些知识,所以,我们这一小节主要是通过日期类来对前面的知识进行巩固。
如果已经忘记相关知识的同学可以查阅以下博客:
https://blog.csdn.net/pusue_the_sun/article/details/149805424?spm=1011.2415.3001.10575&sharefrom=mp_manage_link
https://blog.csdn.net/pusue_the_sun/article/details/149873106?spm=1011.2415.3001.10575&sharefrom=mp_manage_link
https://blog.csdn.net/pusue_the_sun/article/details/149873106?spm=1011.2415.3001.10575&sharefrom=mp_manage_link
现在就正式开始切入正题吧。
日期类的创建
我们先来对日期类中的成员变量和相关方法(成员函数)进行声明:
//日期类的创建
class Date
{
public://日期类中相关方法的实现——函数//构造函数的声明Date(int year = 1, int month = 2, int day = 2);//拷贝构造函数的声明Date(const Date& d);//赋值运算符重载函数Date& operator=(const Date& d);//日期类中成员的打印void Print();//利用赋值重载运算符进行日期类的比较与加减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);// 日期 += 天数Date& operator+=(int day);Date operator+(int day);// 日期 -= 天数Date& operator-=(int day);Date operator-(int day);// 日期相减得到两个日期之间相隔的天数int operator-(const Date& d);//日期的前置++与后置++Date& operator++();Date operator++(int);//日期的前置--与后置--Date operator--();Date operator--(int);private://日期类中的成员int _year;int _month;int _day;};
上面的日期类的实现就是我们本小节的重点内容,大家做好准备迎接今天的挑战了么,我们开始吧!!
默认成员函数的实现
上面我们只写了默认构造函数、赋值运算符重载函数,拷贝构造函数,实际上在前面的内容中我们还学习了析构函数,但是日期类中并没有申请相关的资源,所以编译器自动生成的析构函数就已经足够我们使用了。其实默认构造函数、赋值运算符重载函数,拷贝构造函数这三种函数也可以让编译器帮我们实现,但是我们还是来自己敲一下代码熟悉一下这个过程:
//成员函数中的第一个参数都是隐含的this指针,大家不要忘记了哦//构造函数
//注意要指定类域哦
//注意全缺省构造函数声明和定义分离时只在声明处指定缺省参数的缺省值哦
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}//拷贝构造函数的声明
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}//赋值运算符重载的实现
//为了能够实现连续赋值,赋值重载运算符存在返回值
//我们不期望形参改变影响实参,所以需要在形参引用的前面加上const修饰
Date& Date::operator=(const Date& d)
{this->_year = d._year;this->_month = d._month;this->_day = d._day;return *this;
}
日期类中成员的打印
void Date::Print()
{cout << _year << "-" << _month << "-" << _day<<endl;
}
日期类的运算
这里就是我们这一小节的重点了,虽然这里不难,但大家还是要亲自敲一敲代码。
比较小于
逻辑见注释:
bool Date::operator<(const Date& d)
{//比较小于的逻辑:如果年数较小,那就肯定小//如果年数相等,月份小的,那就肯定小//如果年数相等,月数相等,天数小的,那就肯定小//其他情况,肯定不满足小于条件,返回false即可if (_year < d._year)return true;else if (_year == d._year){if (_month < d._month)return true;else if (_month == d._month)return _day < d._day;}return false;
}
比较等于
bool Date::operator==(const Date& d)
{return((_year == d._year) && (_day == d._day) && (_month == d._month));
}
写完这两个代码,我们可以想一下,对于其他比较逻辑的代码,我们还需要像上面两个函数一样一步一步顺着逻辑写下去嘛?当然是没有必要的,我们可以复用之前代码的逻辑:
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. 保证绝对的一致性 & 正确性
-
所有复用的运算符(
!=
,>
,>=
,<=
)其行为都完全依赖于底层两个核心运算符(==
和<
)的正确性。 -
只要
operator==
和operator<
是正确的,其他运算符就不可能是错误的。这彻底避免了在重写每个运算符时可能引入的细微逻辑错误。
2. 大幅提升可维护性
-
单一修改点: 如果未来需要改变比较逻辑(例如修改时区规则或比较算法),您只需要修改
operator==
和operator<
这两个函数。所有其他相关的运算符会自动继承新的行为,无需逐个修改。 -
降低维护成本: 维护一段代码比维护六段代码要容易得多。
3. 遵循优秀的设计原则
-
消除了重复的、相同的比较逻辑代码。没有重复,就意味着没有因复制粘贴而导致的不一致。
-
单一职责原则: 每个运算符只做一件事并且做好。核心运算符(
<
,==
)负责实现真正的比较逻辑,而派生运算符(>
,>=
等)只负责组合这些逻辑,职责非常清晰。
4. 简化调试和测试
-
调试范围最小化: 如果比较出现Bug,您几乎可以100%确定问题出在
operator==
或operator<
中。您不需要去检查所有6个运算符,极大地缩小了排查范围。 -
测试更高效: 您只需要对
operator==
和operator<
进行 exhaustive (穷尽) 的测试。一旦它们通过测试,您就可以对基于它们构建的其他运算符抱有极高的信心,从而减少大量的测试用例。
5. 提高开发效率和代码简洁性
-
编写更快: 用一两行代码实现一个运算符,远比重新写一套完整的比较逻辑要快。
-
代码更简洁: 代码量大大减少,看起来非常清晰、干净、优雅。例如,
operator!=
的实现return !(*this == d);
就像数学定义一样直观,可读性极强。
日期+天数 / 日期+=天数
举例:假如日期是8月9日,如果我们加上100天,那么得到的日期应该如何计算?
我们可以模拟加法中的进位来计算:
直接将9加上100,得到109,但这是不合理的日期,他已经超出8月的最大日期31了,这时候我们就要开始向月进行进位,8月进到9月,那就要加上31天,那么现在的日期相应的就要减去31天,进位后,得到的日期是9月78日,78超出了9月最大日期30,仍然需要往前进位,得到10月48日,48仍然超出了10月的最大日期31,所以仍然需要往前进位,得到11月17日,17小于11月的最大天数30,所以已经得到了我们最终想要转换的日期即11月17日。
我们通过代码来实现以下上面的过程:
首先我们需要写一个函数来得到某一年的某一个月有多少天,这个函数逻辑比较简单,我们也可以直接将这个函数的定义写到类里面作为成员函数:
//得到某个月的天数
//得到一月有多少天:int GetDayOfMonth(int year, int month){int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))){arr[month]++;}return arr[month];}
现在我们就可以依照上面计算的逻辑来完成日期加法的函数:
Date Date::operator+(int day)
{this->_day += day;while (this->_day > GetDayOfMonth(_year, _month)){_day -= GetDayOfMonth(_year, _month);_month++;//特殊情况处理if (_month == 13){_year++;_month = 1;}}return *this;
}
我们再来测试一下这个函数:
我们发现d2确实是我们分析得到的结果,但是大家伙有没有发现上面那个代码的啥问题没有,那就是d1也发生了改变,但是对于加法,我们是不需要改变d1的值的,实际上,上面我们写的代码逻辑应该是+=的逻辑,因为+=会改变d1,既然发现了错误,就要及时改正,我们来修改一下:
// 日期 += 天数
Date& Date::operator+=(int day)
{this->_day += day;while (this->_day > GetDayOfMonth(_year, _month)){_day -= GetDayOfMonth(_year, _month);_month++;//特殊情况处理if (_month == 13){_year++;_month = 1;}}return *this;
}
上面代码我们使用了传引用返回,因为返回的并不是一个局部对象,所以满足传引用返回的条件,而传引用返回相对于传值返回可以减少拷贝提高效率。
其实日期+天数和日期+=天数的逻辑是十分相似的,无非就是进行+或+=的对象是否需要改变而已,我们可以创建一个临时对象来完成+的逻辑:
Date Date::operator+(int day)
{//this指针指向的对象不会发生改变,所以我们需要创建一个大小与*this相等的对象//后续直接对这个临时对象进行操作即可Date tmp(*this);tmp._day +=day;while (tmp._day > GetDayOfMonth(tmp._year, tmp._month)){tmp._day -= GetDayOfMonth(tmp._year, tmp._month);tmp._month++;if (tmp._month == 13){tmp._year++;tmp._month = 1;}}return tmp;
}
测试一下代码:
可以看到运行结果与预期相符。
上面我们可以看到+和+=的逻辑是十分相似的,那我们就可以考虑写出一个函数后,让另一个函数复用这个函数的功能:
让+=复用+:
Date Date::operator+(int day)
{//this指针指向的对象不会发生改变,所以我们需要创建一个大小与*this相等的对象//后续直接对这个临时对象进行操作即可Date tmp(*this);tmp._day +=day;while (tmp._day > GetDayOfMonth(tmp._year, tmp._month)){tmp._day -= GetDayOfMonth(tmp._year, tmp._month);tmp._month++;if (tmp._month == 13){tmp._year++;tmp._month = 1;}}return tmp;
}// 日期 += 天数
Date& Date::operator+=(int day)
{*this = *this + day;return *this;
}
让+复用+=:
// 日期 += 天数
Date& Date::operator+=(int day)
{this->_day += day;while (this->_day > GetDayOfMonth(_year, _month)){_day -= GetDayOfMonth(_year, _month);_month++;//特殊情况处理if (_month == 13){_year++;_month = 1;}}return *this;
}Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}
既然上面两个逻辑都可以,那哪一个更好呢?
我们先来分析一下第一个代码:在实现+的函数中,共有两处需要调用拷贝构造函数的地方:
Date tmp(*this);
return tmp;
+=复用+以后,里面的+的逻辑需要调用拷贝构造,共有两次。
所以上述两个函数调用了4次拷贝构造。
再来看第二个代码,:在实现+=的函数中,共有0次拷贝构造,在+复用+=的函数中,共有2次拷贝构造:
Date tmp(*this);
return tmp;
所以第二个代码的逻辑会产生2次拷贝构造。
所以第二种代码更好。
日期-=天数 / 日期-天数
结合+和+=函数的实现,我们得出了经验,我们可以先写出-=的逻辑,然后再让-复用-=的逻辑。
如何实现-=的逻辑?来举一个例子:
假设我们要计算8月9号减去50天得到的日期,我们可以像平常数学中的减法中采用借位运算:先让9-50,得到8月-41日,-41并不是一个合法的日期,那我们就要向前面借一位,在这里我要问一下兄弟们,我们向月份借位借的是8月的还是7月的?这个是一个易错点,我们应该向7月借位,因为8月的天数已经减完了,7月一共有31天,借位后的结果是7月(-41+31=-10)日,-10这个日期仍然不合法,所以还是要往前面(6月)借位,6月一共有30天,所以结果是6月20日,20是一个合法的日期号,所以就是最终的结果啦。
我们来依照上面的逻辑写一下代码:
// 日期 -= 天数
Date& Date::operator-=(int day)
{_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetDayOfMonth(_year, _month);}return *this;
}Date Date::operator-(int day)
{Date tmp(*this);tmp -= day;return tmp;
}
我们再来测试一下:
看上去我们的代码好像没有什么问题了,如果我们传入的day是一个负数,又会产生什么样的效果?
可以看到,发生了严重错误,如果是+或+=,也会出现日期不合法的情况。
所以应该怎么解决?
我们知道,减去一个负数就相当于加上一个正数,加上一个负数相当于减去一个正数,这样的话,我们就可以对传入的day是负数的情况下进行特殊处理:
// 日期 += 天数
Date& Date::operator+=(int day)
{if (day < 0){*this -= (-day);return *this;}this->_day += day;while (this->_day > GetDayOfMonth(_year, _month)){_day -= GetDayOfMonth(_year, _month);_month++;//特殊情况处理if (_month == 13){_year++;_month = 1;}}return *this;
}Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}// 日期 -= 天数
Date& Date::operator-=(int day)
{if (day < 0){*this += (-day);return *this;}_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetDayOfMonth(_year, _month);}return *this;
}Date Date::operator-(int day)
{Date tmp(*this);tmp -= day;return tmp;
}
上面我们就完成了+、+=、-、-=的完整逻辑。
日期的前置++和后置++ 前置--和后置--
前置++和后置++所使用的运算符都是++,那么我们应该如何区分它们?
重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。C++规定,后置++重载时,增加一个int形参,跟前置++构成函数重载,方便区分。
前置和后置++我们直接复用前面+或+=代码的逻辑即可:
//日期的前置++与后置++
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)
{Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1;}int day = 0;while (max != min){day++;++min;}return flag * day;
}
使用标准流的重载对类的对象进行输入和输出
我们之前说过,cout和cin是可以自动识别内置类型并进行输入和输出的,但是他不能支持自定义类型,实际上,cout<<和cin<<之所以能自动识别类型,是因为函数重载,cout和cin分别是ostream和istream类的对象(关于ostream类和istream类我们后期还会进行深入探讨,此处只需简单了解即可),当我们进行输入输出的时候,实际上是一个函数调用,比如:
int i;
double d;
cout<<i 等价于 cout.operator<<(i)
cout<<d 等价于 cout.operator<<(d)
现在如果我们要写一个关于日期类的流输出重载运算符应该怎么做?
我们可以直接在类里面定义一个重载函数,那么这个重载函数的第一个形参就是this指针,同时我们还需要传入ostream类的对象,结合这些,我们就能写出相应的函数重载:
//注意是引用传参哦
void Date::operator<<(ostream& out)
{out << _year << "-" << _month << "-" << _day << endl;
}
现在我们就来试着调用一下这个函数:
说明我们写的函数确实可以达成目的,那现在我们就是用运算符的形式来调用一下函数重载:
我们发现,代码报错了,这是怎么回事?
我们之前说过, 重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。一元运算符有一个参数,二元运算符有两个参数,二元运算符的左侧运算对象传给第一个参数,右侧运算对象传给第二个参数。
而在一开始就说过,这个重载运算符函数的第一个参数就是this指针,所以如果我们要写成运算符调用函数重载的形式,应当按照如下的写法:
但是我们进行重载运算符的目的就是让代码的可读性更高,如果想上面那种写法,代码的可读性就比较低,并没有达到我们的诉求,也许有小伙伴认为,那我们调换一下参数的位置不就好了吗?但是,如果是类里面的成员函数,他的第一个参数就一定是this指针,这是无法改变的事实。那有什么好的解决办法呢?
既然重载为类的成员函数行不通,那我们重载为全局函数把ostream/istream放到第一个形参位置就可以了,第二个形参位置当类类型对象不就能解决问题了。
但是接下来又遇到一个问题,就是类里面的成员变量_year,_month,_day都是私有成员,在类外面是不能访问的,这个要怎么解决?
解决方法其实是有好几种的:
1.我们可以再类里面提供一些函数接口,返回值就是类里面的成员变量,通过调用这些成员函数就可以访问这些成员变量。
2.使用友元函数。友元函数的具体概念我们将在下一节讲解,但其实友元函数的使用是十分简单的,我们在这一节可以先看看它是如何使用的。
方法1:
//在类中提供这些函数接口://日期类的创建
class Date
{
public://日期类中相关方法的实现——函数//构造函数的声明Date(int year = 1, int month = 2, int day = 2);//拷贝构造函数的声明Date(const Date& d);//赋值运算符重载函数Date& operator=(const Date& d);//日期类中成员的打印void Print();//得到某个月的天数
//得到一月有多少天:int GetDayOfMonth(int year, int month){int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))){arr[month]++;}return arr[month];}//利用赋值重载运算符进行日期类的比较与加减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);// 日期 += 天数Date& operator+=(int day);Date operator+(int day);// 日期 -= 天数Date& operator-=(int day);Date operator-(int day);// 日期相减得到两个日期之间相隔的天数int operator-(const Date& d);//日期的前置++与后置++Date& operator++();Date operator++(int);//日期的前置--与后置--Date operator--();Date operator--(int);int GetYear(){return _year;}int GetMonth(){return _month;}int GetDay(){return _day;}private://日期类中的成员int _year;int _month;int _day;};void operator<<(ostream& out,Date& d)
{out <<d. GetYear() << "-" << d.GetMonth() << "-" << d.GetDay() << endl;
}
现在我们再来测试一下:
方法2:友元函数
我们只需要在类中加入函数的声明,然后再在声明前加上关键字friend即可:
//日期类的创建
class Date
{friend void operator<<(ostream& out, Date& d);
public://日期类中相关方法的实现——函数//构造函数的声明Date(int year = 1, int month = 2, int day = 2);//拷贝构造函数的声明Date(const Date& d);//赋值运算符重载函数Date& operator=(const Date& d);//日期类中成员的打印void Print();//得到某个月的天数
//得到一月有多少天:int GetDayOfMonth(int year, int month){int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))){arr[month]++;}return arr[month];}//利用赋值重载运算符进行日期类的比较与加减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);// 日期 += 天数Date& operator+=(int day);Date operator+(int day);// 日期 -= 天数Date& operator-=(int day);Date operator-(int day);// 日期相减得到两个日期之间相隔的天数int operator-(const Date& d);//日期的前置++与后置++Date& operator++();Date operator++(int);//日期的前置--与后置--Date operator--();Date operator--(int);int GetYear(){return _year;}int GetMonth(){return _month;}int GetDay(){return _day;}private://日期类中的成员int _year;int _month;int _day;};void operator<<(ostream& out,Date& d)
{out <<d. _year << "-" << d._month<< "-" << d._day << endl;
}
但是,需要注意的是,上面我们的函数并不能支持连续输出:
这要怎么解决呢?
其实也简单,我们只需给函数增加一个返回值即可:
ostream& operator<<(ostream& out,Date& d)
{out <<d. _year << "-" << d._month<< "-" << d._day << endl;return out;
}
来测试一下:
代码整合
头文件Date.h
#pragma once
#include<iostream>
using namespace std;//日期类的创建
class Date
{friend ostream& operator<<(ostream& out, Date& d);
public://日期类中相关方法的实现——函数//构造函数的声明Date(int year = 1, int month = 2, int day = 2);//拷贝构造函数的声明Date(const Date& d);//赋值运算符重载函数Date& operator=(const Date& d);//日期类中成员的打印void Print();//得到某个月的天数
//得到一月有多少天:int GetDayOfMonth(int year, int month){int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))){arr[month]++;}return arr[month];}//利用赋值重载运算符进行日期类的比较与加减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);// 日期 += 天数Date& operator+=(int day);Date operator+(int day);// 日期 -= 天数Date& operator-=(int day);Date operator-(int day);// 日期相减得到两个日期之间相隔的天数int operator-(const Date& d);//日期的前置++与后置++Date& operator++();Date operator++(int);//日期的前置--与后置--Date operator--();Date operator--(int);int GetYear(){return _year;}int GetMonth(){return _month;}int GetDay(){return _day;}private://日期类中的成员int _year;int _month;int _day;};ostream& operator<<(ostream& out, Date& d);
源文件test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"void Test1()
{Date d1(2025, 8, 9);Date d2 = d1 + 100;d1.Print();d2.Print();
}
void Test2()
{Date d1(2025, 8, 9);d1+= 100;d1.Print();
}void Test3()
{Date d1(2025, 8, 9);d1 -= -50;d1.Print();
}void Test4()
{Date d1(2025, 8, 9);Date d2 = d1 - (-50);d1.Print();d2.Print();
}void Test5()
{Date d1(2025, 8, 9);Date d2 = ++d1;d1.Print();d2.Print();
}void Test6()
{Date d1(2025, 8, 9);Date d2 =d1++;d1.Print();d2.Print();
}void Test7()
{Date d1(2025, 6, 7);Date d2(2025, 6, 20);bool ret = d1 < d2;//cout << ret << endl;cout << (d1 - d2) << endl;
}void Test8()
{Date d1(2025, 6, 7);cout << d1;Date d2(2025, 6, 20);cout << d1 << d2;
}int main()
{//Test1();//Test2();//Test3();//Test4();//Test5();//Test6();//Test7();Test8();return 0;
}
源文件Date.cpp
#define _CRT_SECURE_NO_WARNINGS 1#include"Date.h"//成员函数中的第一个参数都是隐含的this指针,大家不要忘记了哦//构造函数
//注意要指定类域哦
//注意全缺省构造函数声明和定义分离时只在声明处指定缺省参数的缺省值哦
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}//拷贝构造函数的声明
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}//赋值运算符重载的实现
//为了能够实现连续赋值,赋值重载运算符存在返回值
//我们不期望形参改变影响实参,所以需要在形参引用的前面加上const修饰
Date& Date::operator=(const Date& d)
{this->_year = d._year;this->_month = d._month;this->_day = d._day;return *this;
}void Date::Print()
{cout << _year << "-" << _month << "-" << _day<<endl;
}//利用赋值重载运算符进行日期类的比较与加减
bool Date::operator<(const Date& d)
{//比较小于的逻辑:如果年数较小,那就肯定小//如果年数相等,月份小的,那就肯定小//如果年数相等,月数相等,天数小的,那就肯定小//其他情况,肯定不满足小于条件,返回false即可if (_year < d._year)return true;else if (_year == d._year){if (_month < d._month)return true;else if (_month == d._month)return _day < d._day;}return false;
}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((_year == d._year) && (_day == d._day) && (_month == d._month));
}
bool Date::operator!=(const Date& d)
{return !((*this) == d);
}//// 日期 += 天数
//Date& Date::operator+=(int day)
//{
// this->_day += day;
// while (this->_day > GetDayOfMonth(_year, _month))
// {
// _day -= GetDayOfMonth(_year, _month);
// _month++;
// //特殊情况处理
// if (_month == 13)
// {
// _year++;
// _month = 1;
// }
// }
// return *this;
//}
//Date Date::operator+(int day)
//{
// //this指针指向的对象不会发生改变,所以我们需要创建一个大小与*this相等的对象
// //后续直接对这个临时对象进行操作即可
// Date tmp(*this);
//
// tmp._day +=day;
// while (tmp._day > GetDayOfMonth(tmp._year, tmp._month))
// {
// tmp._day -= GetDayOfMonth(tmp._year, tmp._month);
// tmp._month++;
// if (tmp._month == 13)
// {
// tmp._year++;
// tmp._month = 1;
// }
// }
// return tmp;
//}
//
//// 日期 += 天数
//Date& Date::operator+=(int day)
//{
// *this = *this + day;
// return *this;
//}
////上面采用+=复用+,需要调用三次拷贝构造函数// 日期 += 天数
Date& Date::operator+=(int day)
{if (day < 0){*this -= (-day);return *this;}this->_day += day;while (this->_day > GetDayOfMonth(_year, _month)){_day -= GetDayOfMonth(_year, _month);_month++;//特殊情况处理if (_month == 13){_year++;_month = 1;}}return *this;
}Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}// 日期 -= 天数
Date& Date::operator-=(int day)
{if (day < 0){*this += (-day);return *this;}_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetDayOfMonth(_year, _month);}return *this;
}Date Date::operator-(int day)
{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)
{Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1;}int day = 0;while (max != min){day++;++min;}return flag * day;
}ostream& operator<<(ostream& out,Date& d)
{out <<d. _year << "-" << d._month<< "-" << d._day << endl;return out;
}