目录
[三、重载 == 运算符](#三、重载 == 运算符)
[四、== 运算符调用过程](#四、== 运算符调用过程)
[五、重载 > 运算符](#五、重载 > 运算符)
[六、重载 < 运算符](#六、重载 < 运算符)
[七、重载 != 运算符](#七、重载 != 运算符)
[八、重载 >= 和 <= 运算符](#八、重载 >= 和 <= 运算符)
[十一、关于 const 成员函数的说明](#十一、关于 const 成员函数的说明)
一、为什么日期类需要比较运算符重载?
对于内置类型,编译器本身就知道怎么比较。
例如:
cpp
int a = 10;
int b = 20;
cout << (a > b) << endl;
cout << (a == b) << endl;
但是对于自定义类型,比如日期类,如果直接写:
cpp
Date d1;
Date d2;
d1 == d2;
d1 > d2;
编译器不知道两个日期类怎么比较。
日期相等,需要判断:
cpp
年相等 && 月相等 && 日相等
日期大小,需要按照:
cpp
先比较年
年相同再比较月
年月相同再比较日
所以我们需要自己重载比较运算符。
二、日期类基本结构
先写一个简单日期类:
cpp
#include <iostream>
using namespace std;
class Date {
public:
Date(int year = 2024; int month = 1; int day = 1) {
_year = year;
_month = month;
_day = day;
}
void Print() {
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
接下来我们子啊这个类中重载比较运算符。
三、重载 == 运算符
两个日期相等,需要满足:
cpp
年份相等
月份相等
日期相等
所以可以这样写:
cpp
bool operator==(const Date& d) {
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
这里参数写成:
cpp
const Date& d
原因是:
- 使用引用可以避免对象拷贝;
- 使用 const 可以防止函数内部修改右操作数。
示例:
cpp
Date d1(2024, 5, 1);
Date d2(2024, 5, 1);
Date d3(2025, 5, 1);
cout << (d1 == d2) << endl;
cout << (d1 == d3) << endl;
运行结果:
cpp
1
0
四、== 运算符调用过程
当我们写:
cpp
d1 == d2
编译器回转换成类似:
cpp
d1.operator==(d2)
也就是说,d1 是左操作数,通过 this 指针传递;d2 是右操作数,作为参数传递。
所以成员函数形式的双目运算符,只需要写一个参数 。
五、重载 > 运算符
日期比较大小时,按照年、月、日依次判断。
比如:
cpp
2025-1-1 > 2024-12-31
是因为年份更大。
cpp
2024-6-1 > 2024-5-31
是因为年份相同,但月份更大。
cpp
2024-5-2 > 2024-5-1
是因为年月相同,但日期更大。
代码可以这样写:
cpp
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;
}
}
六、重载 < 运算符
小于运算符也类似,只是判断方向反过来:
cpp
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;
}
}
也可以利用已经写好的 > 和 == 来复用逻辑:
cpp
bool operator<(const Date& d) {
return !(*this > d) && !(*this == d);
}
这里:
cpp
*this
表示当前对象。
如果当前对象既不大于 d,也不等于 d,那就说明当前对象小于 d。
七、重载 != 运算符
!= 可以直接复用 ==:
cpp
bool operator!=(const Date& d) {
return !(*this == d);
}
如果两个日期不相等,那就是 != 为真。
这样写比重新判断年月日更简洁。
八、重载 >= 和 <= 运算符
>= 可以复用 > 和 ==:
cpp
bool operator>=(const Date& d) {
return (*this > d) || (*this == d);
}
<= 可以复用 < 和 ==:
cpp
bool operator<=(const Date& d) {
return (*this < d) || (*this == d);
}
这样可以减少重复代码。
九、完整代码示例
cpp
#include <iostream>
using namespace std;
class Date {
public:
Date(int year = 2024, int month = 1, int day = 1) {
_year = year;
_month = month;
_day = day;
}
bool operator==(const Date& d) {
return _year == d._year
&& _month == d._month
&& _day == d._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;
}
}
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) || (*this == d);
}
bool operator<=(const Date& d) {
return (*this < d) || (*this == d);
}
private:
int _year;
int _month;
int _day;
};
int main() {
Date d1(2024, 5, 1);
Date d2(2024, 5, 2);
Date d3(2024, 5, 1);
cout << (d1 == d1) << endl;
cout << (d2 > d1) << endl;
cout << (d1 < d2) << endl;
cout << (d1 != d2) << endl;
return 0;
}
运行结果:
cpp
1
1
1
1
十、为什么要复用已有运算符?
如果每一个比较运算符都要重新写一遍年月日判断,代码会比较重复,这是我们不愿意看到的。
例如:
cpp
operator==
operator!=
operator>
operator<
operator>=
operator<=
这些函数之间有很多逻辑是可以复用的。
比如:
cpp
!= 可以复用 ==
>= 可以复用 > 和 ==
<= 可以复用 < 和 ==
这样写的好处是:
- 减少重复代码;
- 逻辑更清晰;
- 后期修改更方便;
- 出错概率更低。
十一、关于 const 成员函数的说明
严格来说,像这些函数:
cpp
bool operator==(const Date& d)
bool operator>(const Date& d)
他们只是比较两个日期,并不会修改当前对象。
所以更规范的写法应该是:
cpp
bool operator==(const Date& d) const
bool operator>(const Date& d) const
后面的 const 表示这个成员函数不会修改当前对象。
不过 const 成员函数会单独后面再讲,这里先知道:不修改成员变量的成员函数,后面一般都建议加 const。
十二、小结
本篇主要学习了日期类中的比较运算符重载。
需要记住:
- 自定义类型比较需要自己定义规则;
- 日期相等要判断年、月、日都相等;
- 日期比较大小要按照尼恩、月、日顺序判断;
- d1 == d1 会转换成 d1.operator==(d2);
- 成员函数形式中,左操作数通过 this 指针传递;
- 参数建议使用 const Date&,避免拷贝防止修改右操作数;
- != 可以 复用 ==;
- >= 可以复用 > 和 ==;
- <= 可以复用 < 和 ==;
- 不修改成员变量的比较函数,后面应写成 const 成员函数。
日期类比较运算符是运算符重载的经典练习。理解比较运算符后,后面在实现日期加减天数、自增自减、日期减日期就会更顺。