[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;

;

[C++]

 此项目为正式的日期类项目,因为我们可以多文件存储。主要包含以下文件:

[C++][C++]

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];

[C++]

由于每年有12个月份,每个月的天数存在微小差别,因此我们选择用数组存放对应月份的天数。这里我们月份对应的下标放对应月份的天数,方面调用。由于我们会多次调用此函数,并且我们不会对其中的内容进行更改。因此我们可以将开辟的数组放在静态区。只需要一次初始化可以实现多次调用的功能。提高的程序的效率。 

由于闰年和平年的2月份天数存在差别,因此我们要对2月份这种特殊情况进行判断,如果是闰年就直接返回29,如果是平年就正常返回。

//判断是否闰年
bool isLeapYear(int year)

return (year % 100 != 0 && year % 4 == 0) || (year % 400 == 0);

[C++]

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);

[C++]

2. operator ==

要判断两个日期是否相等,需要判断两个日期的年月日分别相等。因此我们需要对三个结果进行逻辑与判断,最终返回布尔结果。

bool Date::operator==(const Date& d)

return _year == d._year && _month == d._month && _day == d._day;

[C++]

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;

[C++]

4.operator <=

由于我们已经书写了<和==,因此如果我们要判断<=我们只需要复用上述写好的两个接口即可。逻辑为<和==都满足<=。因此<和==满足其中一个即可返回true,否则返回false.

bool operator <= (const Date& d)

return *this < d || *this == d;

[C++]

5.operator !=

!=和==构成逻辑非,两个接口逻辑相反,因此只需要给==取反即可。

bool operator != (const Date& d)

return !(*this == d);

[C++]

6.operator >

>和<=构成逻辑非,因此只需要对<=取反即可。

bool operator>(const Date& d)

return !(*this <= d);

[C++]

7.operator >= 

>=和<构成逻辑非,因此只需要对<取反即可

bool operator>=(const Date& d)

return !(*this < d);

[C++]


我们发现,我们只需要实现==和<(或>)两个接口即可实现所有的比较接口,由于复用的接口代码量偏少,使用频繁。因此我们可以将后面复用其他接口的接口置成内敛(inline)函数。因此我们可以写在类中。因为类中默认成员函数为内敛函数。


8.operator+=(int day) 日期+=天数

根据逻辑可知,一个日期加上一个天数,将返回一个新的日期。因此这里函数的返回值应为一个日期类Date。

为了实现这个接口,我们可以举例来进行分析:

[C++][C++]

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;

[C++]

测试结果:2022-8-27  经过验证正确。

[C++][C++]

需要注意的是:如果传入的day小于0,我们先对day取相反数再处理即可。 

9.operator+(int day) 日期+天数

由于我们已经实现了日期+=天数,因此我们可以复用。+=和+唯一的区别是+=改变本身,+不改变。因此我们创建一个新的Date,存放结果即可。

Date Date:: operator+(int day)

Date ret(*this);
ret += day;

return ret;

[C++]

测试结果:此时我们发现d1并没有改变,d2改变了。结果正确。

[C++][C++]

10.operator-=(int day) 日期-=天数

逻辑同+=类似,只需要这里注意一些细节节即可,我们同样可以使用一个例子分析

这里如果要是用--,一定是前置--,因此自身是改之后再使用。

[C++][C++]

需要注意的是:如果传入的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;

[C++]

我们同样使用8月27减去100如果返回5月19说明正确。

测试结果正确

[C++][C++]

11.operator-(int day) 日期-天数

 道理同+=和+的关系相同,同样采用复用。

Date Date::operator-(int day)

Date ret(*this);
ret -= day;

return ret;

[C++]

测试:

[C++][C++]

12.前置++,前置--,后置++,后置--


我们发现前置++和后置++的操作符都是++操作符,并且他们的返回类型,函数名,参数列表都一模一样。那么他们我们应该怎么区别呢?


这个问题其实编译器也考虑到了,因此编译器为了区别前置++和后置++,编译器规定,后置++(或后置--)的参数列表中多穿一个值。此时因为两个函数的参数列表的参数个数不同,两个函数就构成了函数重载。就可以区分两个操作符了。

需要注意的是,加的这个参数是为了区分前置和后置,因此传过来的值无所谓。我们一般可以省略写就直接只写数据类型。

因此:前置++就相当于是+=1,

Date& operator++()

*this += 1;
return *this;

[C++]

前置--就相当于-=1

Date& operator--()

*this -= 1;
return *this;

[C++]

后置++先使用,因此要创建一个tmp存上,再自身++

Date operator++(int)

Date tmp(*this);
*this += 1;
return tmp;

[C++]

后置--先使用,因此要创建一个tmp存上,再自身--

Date operator--(int)//加参数为了区分,与传过来的值无关

Date tmp(*this);
*this -= 1;
return tmp;

[C++]

测试:结果正确

[C++][C++]



注意:由于前置++,前置--,后置++,后置--代码使用次数多,代码篇幅小,因此我们可以写在类内成为内联函数。


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++]

测试:结果正确

[C++][C++]



以上是关于[C++] 类与对象(中) 一篇带你解决运算符重载实例--日期类Date的主要内容,如果未能解决你的问题,请参考以下文章

[ C++ ] C++类与对象(中) 类中6个默认成员函数 -- 运算符重载

C++进一步认识类与对象

C++类与对象(中)

C++类与对象(详解构造函数,析构函数,拷贝构造函数,赋值重载函数)

Java - 一篇带你了解类成员(基本数据类型/包装类/对象/数组)默认值

Java - 一篇带你了解类成员(基本数据类型/包装类/对象/数组)默认值