C++运算符重载的使用——实现日期类
目录
一、声明头文件
二、函数实现
0、cout 输出类
1、cin读取类
2、实现获取某年某月的天数
3、实现全缺省的构造函数
4、实现赋值运算符重载
5、实现日期+=天数
6、实现日期+天数
7、实现日期-=天数
8、实现日期-天数
9、实现后置++
10、实现前置++
11、实现后置--
12、实现前置--
13、实现!=运算符重载
14、实现==运算符重载
15、实现>运算符重载
16、实现>=运算符重载
17、实现<运算符重载
18、实现<=运算符重载
19、得到一个日期从0年0月0日到当前日期的天数
20、实现日期-日期
一、声明头文件
声明日期类需要实现的函数
//声明日期类
class Date
{
//声明友元
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
//打印日期
void print();
// 获取某年某月的天数
int GetMonthDay(int year, int month);
// 全缺省的构造函数
Date(int year = 1, int month = 1, int day = 1);
// 拷贝构造函数
Date(const Date& d);
// 赋值运算符重载
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);
//得到一个日期从0年0月0日到当前日期的天数
int GetTotal();
// 日期-日期 返回天数
int operator-(const Date& d);
private:
//年
int _year;
//月
int _month;
//日
int _day;
};
// cout 输出类
ostream& operator<<(ostream& out, const Date& d);
// cin 读取类
istream& operator>>(istream& in, Date& d);
二、函数实现
0、cout 输出类
由于【cout】本身不支持输出自定义类型,因此这里首先实现【cout】 运算符重载。方便后面的测试
【注意】
这里已经在类中声明了友元函数,因此可以实现为全局函数
// cout 输出类
void operator<<(ostream& out, const Date& d)
{
out << d._year << " " << d._month << " " << d._day << endl;
}
1、cin读取类
【注意】
这里已经在类中声明了友元函数,因此可以实现为全局函数
// cin 读取类
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
2、实现获取某年某月的天数
由于日期的计算需要考虑到很多因素(平年、闰年、大月,小月),因此这里实现一个获取某年某月的天数的函数。方便后续函数的计算
//实现获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{
int arr[] = { -1,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[2]++;
}
return arr[month];
}
3、实现全缺省的构造函数
这里我默认的是1年1月1日
【注意】
因为这里展示的函数声明与函数定义的分开实现,而缺省值只能在声明时实现,因此这里的定义就没有写缺省值了
//实现全缺省的构造函数
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
4、实现赋值运算符重载
返回值类型为【Date&】类型是为了支持连续赋值
//实现赋值运算符重载
Date& Date::operator=(const Date& d)
{
this->_year = d._year;
this->_month = d._month;
this->_day = d._day;
return *this;
}
5、实现日期+=天数
Date& Date::operator+=(int day)
{
//如果日期为负数,改为使用【-=】
if (day < 0)
{
return *this -= day;
}
//加上当前日期
_day += day;
int num = GetMonthDay(_year, _month);
//判断当前天数是否满足当前月份的天数
while (_day > num)
{
//月份进一
_month++;
//月份大于12,年份进一
if (_month > 12)
{
_month = 1;
_year++;
}
_day -= num;
//更新当前月份的天数
num = GetMonthDay(_year, _month);
}
return *this;
}
考虑复用:由于【+=】与【+】的运算逻辑高度相似,因此可以考虑复用
//考虑复用
Date& Date::operator+=(int day)
{
//复用【+】运算符重载
*this = *this + day;
return *this;
}
6、实现日期+天数
// 实现日期+天数
Date Date::operator+(int day)
{
//创建临时变量,【+】运算符不改变自己
Date tmp = *this;
//加上当前日期
tmp._day += day;
int num = GetMonthDay(_year, _month);
//判断当前天数是否满足当前月份的天数
while (tmp._day > num)
{
//月份进一
tmp._month++;
//月份大于12,年份进一
if (tmp._month > 12)
{
tmp._month = 1;
tmp._year++;
}
tmp._day -= num;
//更新当前月份的天数
num = GetMonthDay(tmp._year, tmp._month);
}
return tmp;
}
考虑复用:由于【+】与【+=】的运算逻辑高度相似,因此可以考虑复用
//考虑复用
Date Date::operator+(int day)
{
if (day < 0)
{
return *this + day;
}
Date tmp = *this;
//复用【+=】运算符
tmp += day;
return tmp;
}
7、实现日期-=天数
// 实现日期-=天数
Date& Date::operator-=(int day) {
//减去指定天数
_day -= day;
//判断当前天数是否满足当前月份的天数
while (_day <= 0)
{
//月份减一
_month--;
//月份小于1,年份减一
if (_month <= 0)
{
_month = 12;
_year--;
}
//获取当前月份的天数
int num = GetMonthDay(_year, _month);
//更新当前天数
_day += num;
}
return *this;
}
考虑复用:由于【-=】与【-】的运算逻辑高度相似,因此可以考虑复用
//考虑复用
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this -= day;
}
//复用【-】运算符
*this = *this - day;
return *this;
}
8、实现日期-天数
// 实现日期-天数
Date Date::operator-(int day)
{
if (day < 0)
{
return *this + day;
}
//创建临时变量,【-】运算符不改变自己
Date tmp = *this;
//减去指定天数
tmp._day -= day;
//判断当前天数是否满足当前月份的天数
while (tmp._day <= 0)
{
//月份减一
tmp._month--;
//月份小于1,年份减一
if (tmp._month <= 0)
{
tmp._month = 12;
tmp._year--;
}
//获取当前月份的天数
int num = tmp.GetMonthDay(tmp._year, tmp._month);
//更新当前天数
tmp._day += num;
}
return tmp;
}
考虑复用:由于【-】与【-=】的运算逻辑高度相似,因此可以考虑复用
//考虑复用
Date Date::operator-(int day)
{
if (day < 0)
{
return *this + day;
}
Date tmp = *this;
//复用【-=】运算符
tmp -= day;
return tmp;
}
9、实现后置++
后置++重载时,增加⼀个【int】形参,跟前置++构成函数重载,⽅便区分
// 后置++
Date Date::operator++(int)
{
//创建临时变量,后置【++】运算符先赋值后加1
Date tmp = *this;
//日期加1
_day += 1;
//获取当前月份的天数
int num = GetMonthDay(_year, _month);
//判断当前天数是否满足当前月份的天数
while (_day > num)
{
//月份进一
_month++;
//月份大于12,年份进一
if (_month > 12)
{
_month = 1;
_year++;
}
_day -= num;
//更新当前月份的天数
num = GetMonthDay(_year, _month);
}
return tmp;
}
考虑复用:由于【++】就是本身加1,因此可以考虑复用【+=】
Date Date::operator++(int)
{
Date tmp = *this;
//考虑复用
*this += 1;
return tmp;
}
10、实现前置++
前置【++】不用增加⼀个【int】形参
// 实现前置++
Date& Date::operator++()
{
//日期加1
_day += 1;
//获取当前月份的天数
int num = GetMonthDay(_year, _month);
//判断当前天数是否满足当前月份的天数
while (_day > num)
{
//月份进一
_month++;
//月份大于12,年份进一
if (_month > 12)
{
_month = 1;
_year++;
}
_day -= num;
//更新当前月份的天数
num = GetMonthDay(_year, _month);
}
return *this;
}
考虑复用:由于【++】就是本身加1,因此可以考虑复用【+=】
Date& Date::operator++()
{
//考虑复用
*this += 1;
return *this;
}
11、实现后置--
后置【--】重载时,增加⼀个【int】形参,跟前置++构成函数重载,⽅便区分
// 实现后置--
Date Date::operator--(int)
{
//创建临时变量,后置【--】运算符先赋值后减1
Date tmp = *this;
//日期减1
_day -= 1;
//判断当前天数是否满足当前月份的天数
while (_day <= 0)
{
//月份减一
_month--;
//月份小于1,年份减一
if (_month <= 0)
{
_month = 12;
_year--;
}
//获取当前月份的天数
int num = GetMonthDay(_year, _month);
//更新当前天数
_day += num;
}
return tmp;
}
考虑复用:由于【--】就是本身减1,因此可以考虑复用【-=】
Date Date::operator--(int)
{
//创建临时变量,后置【--】运算符先赋值后减1
Date tmp = *this;
//考虑复用
*this -= 1;
return tmp;
}
12、实现前置--
前置【--】不用增加⼀个【int】形参
// 实现前置--
Date& Date::operator--()
{
//日期减1
_day -= 1;
//判断当前天数是否满足当前月份的天数
while (_day <= 0)
{
//月份减一
_month--;
//月份小于1,年份减一
if (_month <= 0)
{
_month = 12;
_year--;
}
//获取当前月份的天数
int num = GetMonthDay(_year, _month);
//更新当前天数
_day += num;
}
return *this;
}
考虑复用:由于【--】就是本身减1,因此可以考虑复用【-=】
Date& Date::operator--()
{
//考虑复用
*this -= 1;
return *this;
}
13、实现!=运算符重载
// 实现!=运算符重载
bool Date::operator != (const Date& d)
{
if (_year == d._year && _month == d._month && _day == d._day)
return false;
return true;
}
考虑复用:【==】运算符取反就是【!=】
bool Date::operator != (const Date& d)
{
//【==】运算符取反就是【!=】
return !(*this == d);
}
14、实现==运算符重载
bool Date::operator==(const Date& d)
{
//年
if (_year != d._year)
return false;
//月
if (_month != d._month)
return false;
//日
if (_day != d._day)
return false;
return true;
}
考虑复用:【!=】运算符取反就是【==】
bool Date::operator==(const Date& d) {
//【!=】运算符取反就是【==】
return !(*this != d);
}
15、实现>运算符重载
// 实现>运算符重载
bool Date::operator>(const Date& d)
{
if (_year != d._year && _year > d._year)
return true;
if (_year != d._year && _year < d._year)
return false;
if (_month != d._month && _month > d._month)
return true;
if (_month != d._month && _month < d._month)
return false;
if (_day != d._day && _day > d._day)
return true;
if (_day != d._day && _day < d._day)
return false;
return false;
}
考虑复用:【<=】运算符取反就是【>】
bool Date::operator>(const Date& d)
{
//【<=】运算符取反就是【>】
return !(*this <= d);
}
16、实现>=运算符重载
bool Date::operator >= (const Date& d)
{
if (_year != d._year && _year > d._year)
return true;
if (_year != d._year && _year < d._year)
return false;
if (_month != d._month && _month > d._month)
return true;
if (_month != d._month && _month < d._month)
return false;
if (_day != d._day && _day > d._day)
return true;
if (_day != d._day && _day < d._day)
return false;
return true;
}
考虑复用:【<】运算符取反就是【>=】
bool Date::operator >= (const Date& d)
{
//【<】运算符取反就是【>=】
return !(*this < d);
}
考虑复用:【==】和【>】运算符,只要有一个为真,那么整体就为真。 【==】和【>】运算符,都为假,那么整体就为假
bool Date::operator >= (const Date& d)
{
//复用【==】和【>】
if (*this == d || *this > d)
{
return true;
}
return false;
}
17、实现<运算符重载
// 实现<运算符重载
bool Date::operator < (const Date& d)
{
if (_year != d._year && _year < d._year)
return true;
if (_year != d._year && _year > d._year)
return false;
if (_month != d._month && _month < d._month)
return true;
if (_month != d._month && _month > d._month)
return false;
if (_day != d._day && _day < d._day)
return true;
if (_day != d._day && _day > d._day)
return false;
return false;
}
考虑复用:【>=】运算符取反就是【<】
bool Date::operator < (const Date& d)
{
//【>=】运算符取反就是【<】
return !(*this >= d);
}
18、实现<=运算符重载
// 实现<=运算符重载
bool Date::operator <= (const Date& d)
{
if (_year != d._year && _year < d._year)
return true;
if (_year != d._year && _year > d._year)
return false;
if (_month != d._month && _month < d._month)
return true;
if (_month != d._month && _month > d._month)
return false;
if (_day != d._day && _day < d._day)
return true;
if (_day != d._day && _day > d._day)
return false;
return true;
}
考虑复用:【>】运算符取反就是【<=】
bool Date::operator <= (const Date& d)
{
//【>】运算符取反就是【<=】
return !(*this > d);
}
考虑复用:【==】和【<】运算符,只要有一个为真,那么整体就为真。 【==】和【<】运算符,都为假,那么整体就为假
bool Date::operator <= (const Date& d)
{
//复用【==】和【>】
if (*this == d || *this < d)
{
return true;
}
return false;
}
19、得到一个日期从0年0月0日到当前日期的天数
这函数的逻辑牵扯到一些数学逻辑,有兴趣的可以去了解一下
这里我们只需要知道这个函数将返回一个日期从0年0月0日到当前日期的天数
int Date::GetTotal()
{
Date tmp = *this;
if (tmp._month < 3) {
--tmp._year;
tmp._month += 12;
}
return 365 * tmp._year + tmp._year / 4 - tmp._year / 100 + tmp._year / 400 + (153 * tmp._month - 457) / 5 + tmp._day - 306;
}
20、实现日期-日期
【日期 - 日期】得到的是两个日期之间相差的天数
// 实现日期-日期
int Date::operator-(const Date& d)
{
Date tmp = d;
return GetTotal() - tmp.GetTotal();
}