C++类和对象(5)——运算符重载(以日期类为例)
运算符重载的作用
假设我们此时实现了日期类的运算符重载,我们就可以
实现如图的很多功能,完成日期计算器的底层代码。
运算符重载关键字
运算符重载的关键字是operator。
比如你想重载‘+’运算符,那么语法格式就是
返回类型 + operator + ‘+’ +(形参),
以日期类为例,
Date operator+(int day)const;
有const关键字是因为这个重载不修改对象本身(*this)的值,如下图的d1不被改变。
Date d3 = d1 + 100;
以下运算符不能重载:
1. ?:
2. sizeof
3. .
4. ::
5. .*
日期类的运算符重载
以下是日期类的声明,待会逐一实现运算符重载。
#pragma once
#include<iostream>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& out, Date& d);
public:
Date(int year = 1990, int month = 1, int day = 1);
~Date();
int GetMonthDay(int year, int month)
{
static int a[13] = { -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)))
{
return 29;
}
return a[month];
}
Date(const Date& d);
void print()const;
Date& operator=(const Date& d);
Date& operator+=(int day);
Date operator+(int day)const;
Date& operator-=(int day);
Date operator-(int day)const;
Date& operator++();
Date operator++(int);
Date& operator--();
Date operator--(int);
bool operator>(const Date& d)const;
bool operator==(const Date& d)const;
bool operator >= (const Date& d)const;
bool operator < (const Date& d)const;
bool operator <= (const Date& d)const;
bool operator != (const Date& d)const;
int operator-(const Date& d)const;
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& out, Date& d);
构造、拷贝构造、析构函数的实现(非重载内容可跳过)
我以前写过两篇博客介绍构造、拷贝构造、析构函数,感兴趣的朋友可以看看。
http://t.csdnimg.cn/DedK1
http://t.csdnimg.cn/LWuj2
Date::Date(int year, int month, int day) :
_year(year),
_month(month),
_day(day)
{}
Date::~Date() {}
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
重载 =
Date& Date::operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
我们运用的场景如下:
Date d1(2000, 1, 1);
Date d2(2001, 2, 2);
d1 = d2;
当我们重载=时,将d2赋值给d1,改变了d1的值,所以重载=的返回类型为 Date& ,返回*this。
重载+=
要实现日期+天数的功能,我们要先编写一个函数GetMonthDay,这个函数可以直接写在类的声明里。
int GetMonthDay(int year, int month)
{
static int a[13] = { -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)))
{
return 29;
}
return a[month];
}
接着实现+=的重载
Date& Date::operator+=(int day)
{
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month == 13)
{
_month = 1;
++_year;
}
}
return *this;
}
通过while循环实现天数的正确叠加、月份和年份的增加。
注意返回类型是Date&,因为
Date d1(2000, 1, 1);
d1 += d1 + 100;
d1重载+=时,d1的值会被改变 !
重载+
这一步我们可以通过写过的的+=重载偷懒😎
Date Date::operator+(int day)const
{
Date temp = *this;
//+=已经重载过了,可以直接用
temp += day;
return temp;
}
注意返回类型是Date,因为
Date d3 = d1 + 100;
调用的时候是d1重载+,d1的值没有被改变。
重载-=(计算这个日期前x天是几号)
Date& Date::operator-=(int day)
{
_day -= day;
while (_day <= 0)
{
--_month;
if (_month == 0)
{
_month = 12;
--_year;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
重载-
Date Date::operator-(int day)const
{
Date temp = *this;
temp -= day;
return temp;
}
重载前置++
Date& Date::operator++()
{
*this += 1;
return *this;
}
这里也用+=重载偷懒了😉
重载后置++
Date Date::operator++(int)
{
Date temp = *this;
++*this;
return temp;
}
注意,为了区分后置++与前置++,后置++的传参有一个int形参!
并且,后置++的返回值为Date, 前置++的返回值为Date&;
因为:
如上图所示,
d2的值与d1的原始值相等 ,
当d1++用过一次之后,d1的值才会+1.
这也就解释了为什么后置++的返回值为Date, 前置++的返回值为Date&;
后置++需要temp变量存放*this的值。
重载前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
}
用-=偷懒。。
重载后置--
Date Date::operator--(int)
{
Date temp = *this;
--*this;
return temp;
}
重载>
bool Date::operator>(const Date& d)const
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year && _month > d._month)
{
return true;
}
else if (_month == d._month && _day > d._day)
{
return true;
}
return false;
}
重载==
bool Date::operator==(const Date& d)const
{
return (_year == d._year) && (_month == d._month) && (_day == d._day);
}
重载>=
bool Date::operator >= (const Date& d)const
{
return (*this > d) || (*this == d);
}
重载<
bool Date::operator < (const Date& d)const
{
return !(*this >= d);
}
重载<=
bool Date::operator <= (const Date& d)const
{
return !(*this > d);
}
重载!=
bool Date::operator != (const Date& d)const
{
return !(*this == d);
}
重载<<
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << '-' << d._month << '-' << d._day << endl;
return out;
}
这不是Date类的成员函数,而是全局函数。
为了能访问私有成员_year,_month,_day,
我们要把这个函数变成友元函数,如下:
重载>>
//这里的形参Date& d的前面不能添加const关键字,因为d的值待会要改变
istream& operator>>(istream& in, Date& d)
{
cout << "" << endl;
in >> d._year >> d._month >> d._day;
return in;
}
重载-(计算两个时间之间差几天)
int Date::operator-(const Date& d)const
{
Date max = *this;
Date min = d;
if (*this < d)
{
max = d;
min = *this;
}
int ret = 0;
while (min != max)
{
++min;
++ret;
}
return ret;
}
我的另一篇博客讲了详细的实现思路http://t.csdnimg.cn/gk7cK