一.日期类头文件的定义
#include <iostream>
using namespace std;
class Date
{
public:
//全缺省构造函数
Date(int year,int month,int day):
_year(year),
_month(month),
_day(day)
{}
//析构函数
~Date()
{
_year = 0;
_month = 0;
_day = 0;
}
//拷贝构造
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
//赋值运算符重载
Date& operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
int GetMonthDay(int year,int month)
{
static int day[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 day[_month];
}
}
// 日期+=天数
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--();
//>>运算符重载
friend istream& operator>>(istream& input, Date& d);
//<<运算符重载
friend ostream& operator<<(ostream& output, const Date& d);
// >运算符重载
friend bool operator>(const Date& d1,const Date& d2);
// ==运算符重载
friend bool operator==(const Date& d1, const Date& d2);
// >=运算符重载
friend bool operator >= (const Date& d1, const Date& d2);
// <运算符重载
friend bool operator < (const Date& d1, const Date& d2);
// <=运算符重载
friend bool operator <= (const Date& d1, const Date& d2);
// !=运算符重载
friend bool operator != (const Date& d1, const Date& d2);
// 日期-日期 返回天数
friend int operator-(const Date& d1, const Date& d2);
private:
int _year;
int _month;
int _day;
};
二.日期类成员函数的实现
2.1GetMonthDay()
当我们在实现日期的加减时,要频繁的计算当前月的天数,而且根据闰年平年的变化,2月的天数也会跟着变化。所以我们可以实现一个函数,专门用来计算某年某月的天数。
int GetMonthDay(int year,int month)
{
static int day[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 day[_month];
}
}
因为该函数需要频繁地使用,所以直接将其定义在类内,称为内联函数,可以提升效率。而函数内部我们可以用一个数组将每个月存储起来,因为这个数组在程序运行过程中也需要多次使用,所以我们可以将其定义为static,避免每次都要创建这个数组。
2.2流提取和流插入运算符重载
//>>运算符重载
istream& operator>>(istream& input, Date& d)
{
cout << "请依次输入年月日->:";
while (1)
{
input >> d._year >> d._month >> d._day;
//判断输入的年月日是否合法
if (d._month > 12 || d._month <1 || d._day>d.GetMonthDay() || d._day < 1)
{
cout << "非法日期,请重新输插入->:";
}
else
{
break;
}
}
return input;
}
//<<运算符重载
ostream& operator<<(ostream& output, const Date& d)
{
cout << d._year << "/" << d._month << "/" << d._day << endl;
return output;
}
对于输入来说,我们要在用户输入之后对日期进行检查,如果日期非法,我们要提醒用户该日期是非法的,并重新输入。
2.3比较运算符重载
大于号的实现,我们可以将ture的条件挑出来,其他的都是false,到最后返回即可。
// >运算符重载
bool operator>(const Date& d1, const Date& d2)
{
if (d1._year > d2._year)
{
return true;
}
else if (d1._year == d2._year)
{
if (d1._month > d2._month)
{
return true;
}
else if (d1._month == d2._month)
{
if (d1._day > d2._day)
{
return true;
}
}
}
return false;
}
// ==运算符重载
bool operator==(const Date& d1, const Date& d2)
{
if (d1._year == d2._year
&& d1._month == d2._month
&& d1._day == d2._day)
{
return true;
}
return false;
}
剩下的操作符都可以复用大于和等于来实现:
// >=运算符重载
bool operator >= (const Date& d1, const Date& d2)
{
return !(d1 < d2);
}
// <运算符重载
bool operator < (const Date& d1, const Date& d2)
{
return !(d1 > d2 || d1 == d2);
}
// <=运算符重载
bool operator <= (const Date& d1, const Date& d2)
{
return !(d1 > d2);
}
// !=运算符重载
bool operator != (const Date& d1, const Date& d2)
{
return !(d1 == d2);
}
2.4日期加减一个整数
// 日期+天数
Date Date::operator+(int day)
{
Date tmp = *this;
tmp._day += day;
while (tmp._day > tmp.GetMonthDay())
{
tmp._day -= tmp.GetMonthDay();
tmp._month += 1;
if (tmp._month > 12)
{
tmp._year += 1;
tmp._month = 1;
}
}
return tmp;
}
// 日期-天数
Date Date::operator-(int day)
{
Date tmp = *this;
tmp._day -= day;
while (tmp._day < 1)
{
tmp._month -= 1;
if (tmp._month < 1)
{
tmp._year -= 1;
tmp._month = 12;
}
tmp._day += tmp.GetMonthDay();
}
return tmp;
}
我们可以先实现+、-一个整数,因为加减运算符不会改变原操作数,所以在实现时不要改变this,否则结果会出错。
然后我们可以借助+、-来实现+=、-=。
// 日期+=天数
Date& Date::operator+=(int day)
{
*this = *this + day;
return *this;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
*this = *this - day;
return *this;
}
这两个操作符在使用时会改变原操作数,所以我们可以复用加减来快速实现+=、-=的实现。
2.5++、--运算符重载
自增自减运算符也可以复用+=以及-=来实现,只不过要区分是前置还是后置,后置的函数会携带一个int形参,该形参只起到区分作用。
前置++/--,返回++/--之后的值
后置++/--,返回++/--之前的值
/ 前置++
Date& Date::operator++()
{
return *this += 1;
}
// 后置++
Date Date::operator++(int)
{
Date tmp = *this;
*this += 1;
return tmp;
}
// 后置--
Date Date::operator--(int)
{
Date tmp = *this;
*this -= 1;
return tmp;
}
// 前置--
Date& Date::operator--()
{
return *this -= 1;
}
2.6日期减日期
日期相减得到天数,我们可以假设法找到日期大的和日期小的,两个日期直接相减不方便计算,我们可以让小日期++,然后记录加的次数,知道两者相等,加的次数就是之间相差的天数。正数则表示d1<d2,表示将来。负数则表示d1>d2表示过去。
// 日期-日期 返回天数
int operator-(const Date& d1, const Date& d2)
{
int day = 0;
Date max = d2;
Date min = d1;
int flag = 1;
if (max < min)
{
max = d1;
min = d2;
flag = -1;
}
while (max > min)
{
min += 1;
day += 1;
}
return flag*day;
}
三.对函数进行调整
这个日期类涉及到了多个成员函数,而有的成员函数并不会修改其参数,所以我们可以将其定义为const成员函数。
我们在调用构造函数的时候也有可能传非法日期,所以我们可以实现一个日期检查函数,再构造函数中进行检查:
bool Check()
{
if (_month > 12 || _month <1 || _day >GetMonthDay() || _day < 1)
{
return false;
}
return true;
}
我们也可以采取更暴力的手段,直接在构造函数中进行assert断言检查,如果断言失败,程序直接终止: