上一篇《类和对象二》中讲到了重载运算符。本篇文章用重载运算符的使用方法,实现日期类,就是写一个简单的日期计算器,精华在于运算符的重载和对已经定义好的符号的复用。
我们将声明放在类中,定义放在另一个源文件中,实现声明和定义的分离。
目录
1. 两个日期相互比较
1.1 ‘==’重载
声明
定义
注意
1.2 ‘<’重载
声明
定义
1.3 ‘<=’重载
声明
用复用的定义
1.4 ‘>’重载
声明
定义
1.5 ‘>=’重载
声明
定义
1.6 ‘!=’重载
声明
定义
2. 赋值 ‘=’重载
声明
定义
3. 对日期天数进行计算
确定月份天数
声明
定义
判断是否是闰年
定义
3.1 日期加天数 ‘+’的重载
声明
定义
小拓展
3.2 日期加天数 ‘+=’的重载
声明
定义
3.3 +和+=相互复用定义比较
复用+定义+=
复用+=定义 +
到底谁复用谁效果更好呢?
3.4 日期减天数‘-=’的重载
声明
定义
3.5 日期减天数‘-’的重载
声明
用复用 -= 定义 -
4.日期 ++ 和 ++
4.1 ++
直接在类中定义
4.2 --
5. 求日期差,返回天数
声明
思路
第一思路:
第二思路:
定义
Date.h
Date.cpp
// ==运算符重载
bool operator==(const Date& d);
//这里隐含参数为this指针
bool Date::operator==(const Date& d)
{
return _year == d._year&&
_month == d._month&&
_day == d._day;
}
下面我们写其他重载是,也要在 operator 前面指向类域:
// <运算符重载
bool operator < (const Date& d);
要考虑到年小于、年等于月小于、年月相同天小于,这三种情况
bool Date::operator < (const Date& d)
{
if ((_year < d._year) ||
(_year == d._year) && (_month < d._month) ||
(_year == d._year) && (_month == d._month) && (_day < d._day))
{
return true;
}
else
{
return false;
}
}
// <=运算符重载
bool operator <= (const Date& d);
一行搞定,< 和 == 的重载我们已经写过了,在这里我们可以直接使用他们,会方便好多,不需要我们再次将冗余的代码写一次并再次判断逻辑。
bool Date::operator <= (const Date& d)
{
return *this < d || *this == d;
}
// >运算符重载
bool operator>(const Date& d);
直接用复用我们已经写过的 <= :
bool Date::operator>(const Date& d)
{
return !(*this <= d);
}
// >=运算符重载
inline bool operator >= (const Date& d);
直接复用 > 和 == :
bool Date::operator >= (const Date& d)
{
return *this > d || *this == d;
}
或者复用 < :
bool Date::operator >= (const Date& d)
{
return !(*this < d);
}
// !=运算符重载
bool operator != (const Date& d);
复用 == ,取反即可:
bool Date::operator != (const Date& d)
{
return !(*this == d);
}
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& operator=(const Date& d);
返回的就是Date类型,就好比有两个整型变量: a=b ,返回的类型也是整型
为什么要加引用呢?
a.this指针出了函数作用域会销毁,但是this所指向的内容是不会销毁的,因此我们可以考虑使用引用返回
b. 并且如果不用引用返回,同类型的对象传值传参会调用拷贝构造,减少开销,也推荐使用引用返回
Date& Date::operator=(const Date& d)
{
if (*this != d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
对日期进行计算:
比如加上天数减去天数,会涉及到月份或年的增加或减少问题。这里就需要判断天数是否超过当前对应月份天数的限制,月份是否超过12等等。并且对于特殊的2月,我们还需区分闰年和平年。
最后返回的是天数
int GetMonthDay(int year, int month);
//Leapyear(year) 是bool类型,判断是否是闰年
int Date::GetMonthDay(int year, int month)
{
在这里对年和月份进行判定
assert(year >= 0 && month>0 && month<13);
static int MDay[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (month == 2 && Leapyear(year))
{
return 29;
}
else
{
return MDay[month];
}
}
这里要注意为什么在数组前加上 static ,不加也是可以的,但是每次创建时调用此函数,都会开辟出新数组,static 可以保持此数组只初始化一次,使用时再次调用即可,可降低开销,提高效率。
我们直接将此函数在类中定义,将默认他是内联函数:
bool Leapyear(int year)
{
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
return true;
}
else
{
return false;
}
}
// 日期+天数
Date operator+(int day);
这里首先要用到拷贝构造,创建一个临时的日期类,对临时的进行更改,最后返回,就比如 a+3后,a 是不改变的。a = a+3,a才会改变。这里的运算相当于a+3
要考虑天数过大时,边界问题,天数有边界,月份有边界,超过月份的天数限制,月份+1,月份==13时,年+1
按照此逻辑进项实现:
Date Date::operator+(int day)
{
Date ret(*this);
ret._day += day;
while (ret._day>GetMonthDay(ret._year,ret._month))
{
ret._day -= GetMonthDay(ret._year, ret._month);
ret._month++;
if (ret._month == 13)
{
ret._year++;
ret._month = 1;
}
}
return ret;
}
当一个对象取初始化另一个不存在的对象时,调用的是构造拷贝
只有两个存在的对象使用=时,才是赋值
相当于 a=a+b ,a本身会改变
// 日期+=天数
Date& operator+=(int day);
和+的逻辑相同,只不过是直接修改 this 指向的内容,注意这里的返回值与 + 不同,+ 返回的是临时变量,用传值,而这里this会销毁, *this 不会销毁,直接返回 *this即可,返回它本身用引用返回。
判断day为负的情况,复用 -=
+=负值等价于-=正值:
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;
}
简便很多
Date& Date::operator+=(int day)
{
*this = *this + day;
return *this;
}
+= 不复用+来实现,那么+就可以复用 +=来实现
Date Date::operator+(int day)
{
Date ret(*this);
ret += day;
return ret;
}
由拷贝构造的次数来看,+ 复用 += 效率会更高一些。
由此推出:- 复用 -= 效率会更高。
// 日期-=天数
Date& operator-=(int day);
这里特别要注意的是当月份为0,时,重置月份,更新天数的时候,用更新后的月份来计算。
最后返回*this,不会销毁,用引用返回。
判断day为负的情况,复用 +=
-=负值等价于+=正值::
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;
}
// 日期-天数
Date operator-(int day);
Date Date::operator-(int day)
{
Date ret(*this);
ret -= day;
return ret;
}
++运算符重载分为前置++和后置++,他们的函数形式如下:
// 前置++
Date& operator++();
// 后置++
Date operator++(int);
函数名相同,为了区分开来,语法规定:
没有参数的为前置++
有参数的为后置++
前置++,直接改变*this的内容
后置++,*this不变,返回的是此函数中构建好的临时变量,临时变量进行运算操作之后返回
// 前置++
Date& operator++()
{
*this += 1;
return *this;
}
// 后置++
Date operator++(int)
{
Date ret(*this);
ret += 1;
return ret;
}
和++同理,直接在类中定义:
// 后置--
Date operator--(int)
{
Date ret(*this);
ret -= 1;
return ret;
}
// 前置--
Date& operator--()
{
*this -= 1;
return *this;
}
两个日期不相等时,求他们之间相差多少天
// 日期-日期 返回天数
int operator-(const Date& d);
第一思路:
年之间比较求差,月之间比较求差,天之间比较球差,最后判断对应天数,累加即可。
缺点:分别判断,分别计算,过程太繁琐
第二思路:
首先判断谁大谁小,让小的开始累加,直到和大的相等为止,只需要计加了多少天即可。
这里flag来确定正负,如果现在和未来比,天数是正的,加上天数即可和大的相等
如果是现在和过去比,天数是负的,现在+天数等于过去的时间
int Date::operator-(const Date& d)
{
int flag = 1;
Date max = *this;
Date min = d;
if (*this
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include
#include
using std::cout;
using std::cin;
using std::endl;
class Date
{
public:
// 获取某年某月的天数
bool Leapyear(int year)
{
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
return true;
}
else
{
return false;
}
}
int GetMonthDay(int year, int month);
// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1)
{
if (year < 1900 ||
month < 1 || month > 12 ||
day < 1 || day > GetMonthDay(year, month))
{
cout << "非法日期" << endl;
}
_year = year;
_month = month;
_day = day;
}
拷贝构造函数
// d2(d1)
Date(const Date& d)
{
cout << "构造拷贝" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& operator=(const Date& d);
// 析构函数
~Date()
{
}
// 日期+=天数
Date& operator+=(int day);
// 日期+天数
Date operator+(int day);
// 日期-天数
Date operator-(int day);
// 日期-=天数
Date& operator-=(int day);
// 前置++
Date& operator++()
{
*this += 1;
return *this;
}
// 后置++
Date operator++(int)
{
Date ret(*this);
ret += 1;
return ret;
}
// 后置--
Date operator--(int)
{
Date ret(*this);
ret -= 1;
return ret;
}
// 前置--
Date& operator--()
{
*this -= 1;
return *this;
}
// >运算符重载
bool operator>(const Date& d);
// ==运算符重载
bool operator==(const Date& d);
// >=运算符重载
inline bool operator >= (const Date& d);
// <运算符重载
bool operator < (const Date& d);
// <=运算符重载
bool operator <= (const Date& d);
// !=运算符重载
bool operator != (const Date& d);
// 日期-日期 返回天数
int operator-(const Date& d);
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
#define _CRT_SECURE_NO_WARNINGS
#include "Date.h"
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
cout << "赋值" << endl;
if (*this != d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
析构函数
//
//~Date()
// 日期+=天数
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;
//*this = *this + day;
//return *this;
}
// 日期+天数
Date Date::operator+(int day)
{
Date ret(*this);
//ret._day += day;
//while (ret._day>GetMonthDay(ret._year, ret._month))
//{
// ret._day -= GetMonthDay(ret._year, ret._month);
// ret._month++;
// if (ret._month == 13)
// {
// ret._year++;
// ret._month = 1;
// }
//}
ret += day;
return ret;
}
// 日期-天数
Date Date::operator-(int day)
{
Date ret(*this);
ret -= day;
return ret;
}
// 日期-=天数
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;
}
// >运算符重载
bool Date::operator>(const Date& d)
{
//if ((_year > d._year) ||
// (_year == d._year) && (_month > d._month) ||
// (_year == d._year) && (_month == d._month) && (_day > d._day))
//{
// return true;
//}
//else
//{
// return false;
//}
return !(*this <= d);
}
// ==运算符重载
//参数:看运算符来定:两个相比较,那么就有两个形参
//返回值:看运算后的结构,比较相等返回真假即可,即bool
//这里隐含参数为this指针
bool Date::operator==(const Date& d)
{
return _year == d._year&&
_month == d._month&&
_day == d._day;
}
// >=运算符重载
inline bool Date::operator >= (const Date& d)
{
//if ((_year > d._year) ||
// (_year == d._year) && (_month > d._month) ||
// (_year == d._year) && (_month == d._month) && (_day >= d._day))
//{
// return true;
//}
//else
//{
// return false;
//}
return *this > d || *this == d;
//return !(*this < d);
}
// <运算符重载
bool Date::operator < (const Date& d)
{
if ((_year < d._year) ||
(_year == d._year) && (_month < d._month) ||
(_year == d._year) && (_month == d._month) && (_day < d._day))
{
return true;
}
else
{
return false;
}
}
// <=运算符重载
bool Date::operator <= (const Date& d)
{
//if ((_year < d._year) ||
// (_year == d._year) && (_month < d._month) ||
// (_year == d._year) && (_month == d._month) && (_day <= d._day))
//{
// return true;
//}
//else
//{
// return false;
//}
return *this < d || *this == d;
}
// !=运算符重载
bool Date::operator != (const Date& d)
{
/*if ((_year != d._year) ||
(_year == d._year) && (_month != d._month) ||
(_year == d._year) && (_month == d._month) && (_day != d._day))
{
return true;
}
else
{
return false;
}*/
return !(*this == d);
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
int flag = 1;
Date max = *this;
Date min = d;
if (*this= 0 && month>0 && month<13);
static int MDay[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (month == 2 && Leapyear(year))
{
return 29;
}
else
{
return MDay[month];
}
}