[C++] 类与对象(中) 一篇带你解决运算符重载实例--日期类Date
Posted 小白又菜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C++] 类与对象(中) 一篇带你解决运算符重载实例--日期类Date相关的知识,希望对你有一定的参考价值。
上上篇文章我们了解了运算符重载,本篇文章我们将通过一个实例:日期类(Date)来巩固运算符重载的知识。
目录
1.全缺省的构造函数
2. operator ==
3.operator <
4.operator <=
5.operator !=
6.operator >
7.operator >=
8.operator+=(int day) 日期+=天数
9.operator+(int day) 日期+天数
10.operator-=(int day) 日期-=天数
11.operator-(int day) 日期-天数
12.前置++,前置--,后置++,后置--
13.日期-日期
完整代码:
本篇文章我们将主要实现一下接口。
class Date
public:
// 获取某年某月的天数
int GetMonthDay(int year, int month);
// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1);
// 拷贝构造函数
//d2(d1)
Date(const Date& d);
// 赋值运算符重载
// 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++();
// 后置++
Date operator++(int);
// 后置--
Date operator--(int);
// 前置--
Date& operator--();
// >运算符重载
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);
private:
int _year;
int _month;
int _day;
;
此项目为正式的日期类项目,因为我们可以多文件存储。主要包含以下文件:
1.全缺省的构造函数
构造函数类似于初始化,其中需要注意的是要对日期的合法性进行判断。由于每个月份的天数存在差别,这里在day中我们需要调用一个GetMonthDay函数接口。
int Date::GetMonthDay(int year, int month)
assert(year >= 0 && month > 0 && month < 13);
//静态区开一次
static int monthDayArray[13] = 0,31,28,31,30,31,30,31,31,30,31,30,31 ;
if (month == 2 && isLeapYear(year))
return 29;
return monthDayArray[month];
由于每年有12个月份,每个月的天数存在微小差别,因此我们选择用数组存放对应月份的天数。这里我们月份对应的下标放对应月份的天数,方面调用。由于我们会多次调用此函数,并且我们不会对其中的内容进行更改。因此我们可以将开辟的数组放在静态区。只需要一次初始化可以实现多次调用的功能。提高的程序的效率。
由于闰年和平年的2月份天数存在差别,因此我们要对2月份这种特殊情况进行判断,如果是闰年就直接返回29,如果是平年就正常返回。
//判断是否闰年
bool isLeapYear(int year)
return (year % 100 != 0 && year % 4 == 0) || (year % 400 == 0);
Date::Date(int year, int month, int day)
if (year >= 1 && month <= 12 && month >= 1 && day >= 1 && day <= GetMonthDay(year, month))
_year = year;
_month = month;
_day = day;
else
cout << "您输入的日期不合法" << endl;
exit(-1);
2. operator ==
要判断两个日期是否相等,需要判断两个日期的年月日分别相等。因此我们需要对三个结果进行逻辑与判断,最终返回布尔结果。
bool Date::operator==(const Date& d)
return _year == d._year && _month == d._month && _day == d._day;
3.operator <
要判断日期<日期。
1、首先要比较对应的年,如果年小后面无需比较,直接返回true.
2、如果年相同,再比较月,如果月小无需比较天,直接返回true.
3、如果年月都相同,此时比较天,如果天小返回true.
因此以上3种情况满足任意一种就返回true,否则返回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 false;
else
return true;
4.operator <=
由于我们已经书写了<和==,因此如果我们要判断<=我们只需要复用上述写好的两个接口即可。逻辑为<和==都满足<=。因此<和==满足其中一个即可返回true,否则返回false.
bool operator <= (const Date& d)
return *this < d || *this == d;
5.operator !=
!=和==构成逻辑非,两个接口逻辑相反,因此只需要给==取反即可。
bool operator != (const Date& d)
return !(*this == d);
6.operator >
>和<=构成逻辑非,因此只需要对<=取反即可。
bool operator>(const Date& d)
return !(*this <= d);
7.operator >=
>=和<构成逻辑非,因此只需要对<取反即可
bool operator>=(const Date& d)
return !(*this < d);
我们发现,我们只需要实现==和<(或>)两个接口即可实现所有的比较接口,由于复用的接口代码量偏少,使用频繁。因此我们可以将后面复用其他接口的接口置成内敛(inline)函数。因此我们可以写在类中。因为类中默认成员函数为内敛函数。
8.operator+=(int day) 日期+=天数
根据逻辑可知,一个日期加上一个天数,将返回一个新的日期。因此这里函数的返回值应为一个日期类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;
测试结果:2022-8-27 经过验证正确。
需要注意的是:如果传入的day小于0,我们先对day取相反数再处理即可。
9.operator+(int day) 日期+天数
由于我们已经实现了日期+=天数,因此我们可以复用。+=和+唯一的区别是+=改变本身,+不改变。因此我们创建一个新的Date,存放结果即可。
Date Date:: operator+(int day)
Date ret(*this);
ret += day;
return ret;
测试结果:此时我们发现d1并没有改变,d2改变了。结果正确。
10.operator-=(int day) 日期-=天数
逻辑同+=类似,只需要这里注意一些细节节即可,我们同样可以使用一个例子分析
这里如果要是用--,一定是前置--,因此自身是改之后再使用。
需要注意的是:如果传入的day小于0,我们先对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;
我们同样使用8月27减去100如果返回5月19说明正确。
测试结果正确
11.operator-(int day) 日期-天数
道理同+=和+的关系相同,同样采用复用。
Date Date::operator-(int day)
Date ret(*this);
ret -= day;
return ret;
测试:
12.前置++,前置--,后置++,后置--
我们发现前置++和后置++的操作符都是++操作符,并且他们的返回类型,函数名,参数列表都一模一样。那么他们我们应该怎么区别呢?
这个问题其实编译器也考虑到了,因此编译器为了区别前置++和后置++,编译器规定,后置++(或后置--)的参数列表中多穿一个值。此时因为两个函数的参数列表的参数个数不同,两个函数就构成了函数重载。就可以区分两个操作符了。
需要注意的是,加的这个参数是为了区分前置和后置,因此传过来的值无所谓。我们一般可以省略写就直接只写数据类型。
因此:前置++就相当于是+=1,
Date& operator++()
*this += 1;
return *this;
前置--就相当于-=1
Date& operator--()
*this -= 1;
return *this;
后置++先使用,因此要创建一个tmp存上,再自身++
Date operator++(int)
Date tmp(*this);
*this += 1;
return tmp;
后置--先使用,因此要创建一个tmp存上,再自身--
Date operator--(int)//加参数为了区分,与传过来的值无关
Date tmp(*this);
*this -= 1;
return tmp;
测试:结果正确
注意:由于前置++,前置--,后置++,后置--代码使用次数多,代码篇幅小,因此我们可以写在类内成为内联函数。
13.日期-日期
这个接口我们要实现一个日期与另一个日期之间相差多少天。如果是小日期-大日期,应该返回一个负数。因此我们要对这个小细节进行处理。
这里的实现逻辑是:
1、我们先默认第一个日期为大日期,第二个日期为小日期。
2、我们在对这两个进行比较,如果第一个是小日期,我们就将max和min进行日期调换。如果调换说明是小日期-大日期,最终的结果理应该是个负数。因此我们定义一个flag = 1,如果这里调换的话,让flag = -,最终返回n*flag即可。
3、我们要始终保持小追大。我们使用前置++运算,让小的日期追大的日期,这里需要定义一个计数器n。每++一次,n就++一次。
int Date::operator-(const Date& d)
int flag = 1;
Date max = *this;//默认认为第一大
Date min = d;
if (*this < d)
min = *this;
max = d;
flag = -1;
int n = 0;
while (min != max)
++n;
++min;
return n*flag;
测试:结果正确
以上是关于[C++] 类与对象(中) 一篇带你解决运算符重载实例--日期类Date的主要内容,如果未能解决你的问题,请参考以下文章
[ C++ ] C++类与对象(中) 类中6个默认成员函数 -- 运算符重载
C++类与对象(详解构造函数,析构函数,拷贝构造函数,赋值重载函数)