目录
前言:
class Date {
public:
Date(int year = 1199, int month = 12, int day = 15) {
_year = year;
_month = month;
_day = day;
}
public:
int _year;
int _month;
int _day;
};
int main() {
Date d1(2022, 10, 15);
Date d2(2022, 10, 16);
return 0;
}
我们都知道,在学习C语言的过程中,学过很多运算符的知识,比如:+,-,*,/,%,=,==等,它们都是用来做内置类型数据间的计算,而现在C++有了类(自定义类型),那么对于自定义类型所创建的对象,是不是也可以做这些运算呢?比如上面代码中的日期类,创建出两个对象d1,d2,那么我们是不是可以对这两个对象做运算?d1加减d2,d1是否等于d2,d1是否大或者小于d2等运算操作, 这便是我今天所要讲解的主题了——运算符重载函数,它是类的另一大特殊成员函数。
一.运算符重载
1.定义:
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。它主要是针对自定义类型做运算而研发的。
2.函数名字为:
关键字operator后面接需要重载的运算符符号。
3.函数原型:
返回值类型 operator操作符(参数列表)
1. 不能通过连接其他符号来创建新的操作符:比如operator@
2.重载操作符必须有一个类类型参数 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义 。
3.作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
4. .*运算符、::运算符、sizeof运算符、?:运算符、 .运算符这五种运算符不支持运算重载!!!
练习:对比两个日期类对象是否相等==函数重载
class Date {
public:
Date(int year = 1199, int month = 12, int day = 15) {
_year = year;
_month = month;
_day = day;
}
public:
int _year;
int _month;
int _day;
};
bool operator==(const Date& d1, const Date& d2) { //==运算符重载函数
return (d1._year == d2._year && d1._month == d2._month && d1._day == d2._day);
}
int main() {
Date d1(2022, 10, 15);
Date d2(2022, 10, 16);
cout << (d1 == d2 )<< endl;
return 0;
}
解析:通过创建日期类对象d1,d2去比较他俩是否相等,operator处在类外,因为日期类的成员全都是公共成员,所以类外的函数可以轻易的访问到类内。
重载函数operator==是通过比较两个对象的成员变量,通过布尔类型去判定返回真假值。
d1==d2是隐式调用重载函数operator==的写法,它等价于d1.operator(d2);这句是显式调用,但我们一般不这么写。注:d1==d2要给括号,因为cout<<会有优先级问题!
若日期类中的成员是私有的,那又该怎么办?
这时,我们可以把重载函数放进类内处理,但需要改变函数的形参:
class Date {
public:
Date(int year = 1199, int month = 12, int day = 15) {
_year = year;
_month = month;
_day = day;
}
//将重载函数放在类里面
bool operator==(const Date& d) {
return (_year == d._year && _month == d._month && _day == d._day);
}
private:
int _year;
int _month;
int _day;
};
int main() {
Date d1(2022, 10, 15);
Date d2(2022, 10, 16);
cout << (d1 == d2) << endl; //d1==d2要加括号,否则会引发优先级问题
return 0;
}
形参d就代表是d2,_year,_month,_day都是d1的成员变量。
练习:对比两个日期类对象>,>=的运算符重载函数
class Date {
public:
Date(int year = 1199, int month = 12, int day = 15) {
_year = year;
_month = month;
_day = day;
}
//比较大小——重载
bool operator>(const Date& d) {
if (_year > d._year) {
return true;
}
else if (_year == d._year && _month > d._month) {
return true;
}
else if (_year == d._year && _month == d._month && _day > d._day) {
return true;
}
else {
return false;
}
}
private:
int _year;
int _month;
int _day;
};
int main() {
Date d1(2022, 10, 22);
Date d2(2022, 9, 25);
cout << (d1 > d2) << endl;
}
operator>重载函数中,需要逐年、逐月、逐日的去判定大小!
class Date {
public:
Date(int year = 1199, int month = 12, int day = 15) {
_year = year;
_month = month;
_day = day;
}
bool operator>=(const Date& d) {
if (_year > d._year) {
return true;
}
else if (_year == d._year && _month > d._month) {
return true;
}
else if (_year == d._year && _month == d._month && _day >= d._day) {
return true;
}
else {
return false;
}
}
private:
int _year;
int _month;
int _day;
};
对于大于等于的函数重载,只需要在day上加个=即可,但代码可读性不高,其实我们可以复用operator>的函数重载:
bool operator>=(const Date& d) { //d是d2,*this是d1
return (*this > d || *this == d);
}
解析:*this>d 会调用运算符重载函数operator>,*this==d会调用运算符重载函数operator==
这种写法代码复用性很高,一步就可以解决。
对于小于、小于等于、不等于的函数重载如下:
//判定小于的运算符重载函数
bool operator<(const Date& d) {
return !(*this > d || *this == d);
}
//判定小于等于的运算符重载函数
bool operator<=(const Date& d) {
return !(*this > d);
}
//判定不等于的运算符重载函数
bool operator!=(const Date& d) {
return !(*this == d);
}
练习:日期类对象+=天数的重载函数
对于月份天数的运算,首先要搞清楚每个月有几天,特殊年——闰年2月的天数,相加该怎么加。
算法如图:每当要加的天数超过本月的最大值时,先加起来,然后减去该月的最大值,让其月份+1即可;对于12月来说,若相加的天数超过30天,那么就会到下一年,我们应该让月份归一,年份+1即可;对于2月,还得判定它是否是闰年的二月!得考虑众多情况。
代码如下:
class Date {
public:
Date(int year = 1199, int month = 12, int day = 15) {
_year = year;
_month = month;
_day = day;
}
//判定月份天数
int GetMonthDay(int year, int month) {
int MonthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if ((month == 2) && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {
return 29;
}
return MonthDay[month];
}
//加等于天数重载
Date& operator+=(int day) {
_day += day;
while (_day > GetMonthDay(_year, _month)) {
_day -= GetMonthDay(_year, _month);
_month++;
if (_month == 13) {
_month = 1;
_year++;
}
}
return *this;
}
void Print() {
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main() {
Date d1(2022, 10, 22);
Date d2(2022, 9, 23);
d1 += 5;
d1.Print();
d1 += 10;
d1.Print();
d1 += 50;
d1.Print();
d1 += 100;
d1.Print();
return 0;
}
先获取到每个月的天数,对于闰年二月要做特殊处理,其次就是在重载函数中进行算法编写;最后需要注意一点,传值返回会多进行一次拷贝,为了提高运行效率,应该用引用返回。
而对于operator+重载函数来说,+并不会改变对象,在内置类型中,int a=10;a+10;也照样不会改变变量a的值,只是a+10的返回值是15,所以针对+的重载函数,我们应该用值传递
Date operator+(int day) {
Date ret(*this); //调用拷贝构造
ret += day;
return ret;
}
Date ret(*this)语句会调用该类的拷贝构造函数,也就是说新对象ret会拷贝对象d2的数据,ret虽然+=day了,但这是值传递,形参的改变并不会影响实参,所以d2并不会被改变。
练习:日期类对象- =天数的重载函数:
算法如图:核心思想是借位。先减去天数,若日期小于等于0,则需要去借上个月的最大天数,用于弥补日期的负值,直到补正为止。
Date& operator-=(int day) {
_day -= day;
while (_day <= 0) {
_month--;
if (_month == 0) {
_month = 12;
_year--;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
Date operator-(int day) {
Date ret(*this);//拷贝构造
ret -= day;
return ret;
}