C++学习笔记20:日期类比较运算符重载

目录

一、为什么日期类需要比较运算符重载?

二、日期类基本结构

[三、重载 == 运算符](#三、重载 == 运算符)

[四、== 运算符调用过程](#四、== 运算符调用过程)

[五、重载 > 运算符](#五、重载 > 运算符)

[六、重载 < 运算符](#六、重载 < 运算符)

[七、重载 != 运算符](#七、重载 != 运算符)

[八、重载 >= 和 <= 运算符](#八、重载 >= 和 <= 运算符)

九、完整代码示例

十、为什么要复用已有运算符?

[十一、关于 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

原因是:

  1. 使用引用可以避免对象拷贝;
  2. 使用 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 复制代码
!= 可以复用 ==
>= 可以复用 > 和 ==
<= 可以复用 < 和 ==

这样写的好处是:

  1. 减少重复代码;
  2. 逻辑更清晰;
  3. 后期修改更方便;
  4. 出错概率更低。

十一、关于 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


十二、小结

本篇主要学习了日期类中的比较运算符重载。

需要记住:

  1. 自定义类型比较需要自己定义规则;
  2. 日期相等要判断年、月、日都相等;
  3. 日期比较大小要按照尼恩、月、日顺序判断;
  4. d1 == d1 会转换成 d1.operator==(d2);
  5. 成员函数形式中,左操作数通过 this 指针传递;
  6. 参数建议使用 const Date&,避免拷贝防止修改右操作数;
  7. != 可以 复用 ==;
  8. >= 可以复用 > 和 ==;
  9. <= 可以复用 < 和 ==;
  10. 不修改成员变量的比较函数,后面应写成 const 成员函数。

日期类比较运算符是运算符重载的经典练习。理解比较运算符后,后面在实现日期加减天数、自增自减、日期减日期就会更顺。

相关推荐
paeamecium5 小时前
【PAT甲级真题】- A+B in Hogwarts
c++·算法·pat考试·pat
咩咦6 小时前
C++学习笔记16:构造函数
c++·学习笔记·类和对象·构造函数·默认构造函数
basketball6166 小时前
C++ 嵌套类完全指南:类中类的巧妙设计
开发语言·c++
kyle~6 小时前
ros_gz_bridge---底层通信的实现
c++·机器人·仿真·ros2
Jasmine_llq7 小时前
《B4261 [GESP202503 三级] 2025》
开发语言·c++·算法·条件判断算法·位运算恒等式推导·简单算术运算
小张成长计划..7 小时前
【C++】32:智能指针
c++
咩咦7 小时前
C++学习笔记19:运算符重载基础与赋值运算符重载
c++·学习笔记·类和对象·运算符重载·赋值运算符·operator
无限进步_8 小时前
C++异常机制:抛出、捕获与栈展开
开发语言·c++·安全
王老师青少年编程8 小时前
csp信奥赛C++高频考点专项训练之前缀和&差分 --【一维前缀和】:宝石串
c++·前缀和·csp·高频考点·信奥赛·宝石串