C++学习笔记22:前置后置 ++/-- 和日期减日期

目录

[一、前置 ++ 和后置 ++ 的区别](#一、前置 ++ 和后置 ++ 的区别)

二、前置++的实现

三、后置++的实现

[四、前置 -- 的实现](#四、前置 -- 的实现)

[五、后置 -- 的实现](#五、后置 -- 的实现)

六、日期减日期的意义

七、日期减日期的实现思路

八、处理正负号

九、日期减日期代码示例

十、为什么使用前置++?

十一、完整示例片段

十二、小结


一、前置 ++ 和后置 ++ 的区别

在C++中,++ 有两种形式。

cpp 复制代码
++d;    // 前置++
d++;    // 后置++

对于日期类来说:

cpp 复制代码
++d;

表示日期加一天,并返回加完后的对象。

cpp 复制代码
d++;

也表示日期加一天,但返回的是加之前的旧值。

所以两者的区别是:

cpp 复制代码
前置++:先加,再返回当前对象
后置++:先保存旧值,再加,最后返回旧值

二、前置++的实现

前置++ 可以直接复用前面写过的 operator+=。

因为日期加一天,本质就是:

cpp 复制代码
*this += 1;

代码:

cpp 复制代码
Date& operator++() {
	return *this += 1;
} 

这里返回值是 Date&,也就是当前对象的引用。

原因是:

cpp 复制代码
前置++修改的是当前对象,返回修改后的当前对象

三、后置++的实现

后置++需要返回加之前的旧值。

所以实现步骤是:

cpp 复制代码
1. 保存当前对象的副本。
2. 当前对象加一天;
3. 返回保存的旧值。

代码:

cpp 复制代码
Date operator++(int) {
	Date tmp = *this;
	*this += 1;
	return tmp;
}

这里的 int 参数没有实际使用,他只是来区分前置和后置。

也就是说:

cpp 复制代码
operator++();      // 前置++
operator++(int)    // 后置++

后置 ++ 返回的是值,所以不是引用。

因为 tmp 是函数内部的对象,函数结束后会销毁,不能返回它的引用。


四、前置 -- 的实现

前置 -- 和前置 ++ 类似。

前置 -- 表示日期减一天,先减,再返回当前对象。

可以复用 operator-=:

cpp 复制代码
Date& operator--() {
	return *this -= 1;
}

五、后置 -- 的实现

后置 -- 表示日期减一天,但返回减之前的旧值。

代码:

cpp 复制代码
Date operator--(int) {
	Date tmp = *this;
	*this -= 1;
	return tmp;
}

这里同样使用 int 占位参数区分前置和后置。


六、日期减日期的意义

日期类中,两个日期相加通常是没有实际意义的。

例如:

cpp 复制代码
2024-5-1 + 2024-6-1

这个结果就没有明确意义。

但是两个日期相减是有意义的:

cpp 复制代码
2024-6-1 - 2024-5-1

表示两个日期差多少天。

所以日期类中可以重载:

cpp 复制代码
int operator-(const Date& d);

返回两个日期相差的天数。


七、日期减日期的实现思路

直接做年月日结尾计算比较麻烦。

比如:

cpp 复制代码
2024-1-10 - 2023-12-20

涉及跨年、跨月、不同月份天数、闰年等问题。

一种比较容易理解的思路是:

让比较小的日期不断加一天,直到等于较大的日期,累计加了多少次,就相差多少天。

例如:

cpp 复制代码
2024-5-1 和 2024-5-4

从 2024-5-1 开始:

cpp 复制代码
+1 -> 2024-5-2
+1 -> 2024-5-3
+1 -> 2024-5-4

一共加了 3 次,所以相差 3 天。

这种方法逻辑很简单,而且可以复用前面已经实现的 ++ 和比较运算符。


八、处理正负号

日期减日期还要考虑正负。

例如:

cpp 复制代码
d1 - d2

如果 d1 > d2,结果就应该是正数。

如果 d1 < d2,结果就应该是负数。

可以用一个 flag 标记符号:

cpp 复制代码
如果左边日期较大,flag = 1
如果左边日期较小,flag = -1

最后返回:

cpp 复制代码
count * flag

九、日期减日期代码示例

假设已经实现了:

cpp 复制代码
bool operator<(const Date& d) const;
bool operator!=(const Date& d) const;
Date& operator++();

那么日期减日期可以这样写:

cpp 复制代码
int operator-(const Date& d) const {
	Date max = *this;
	Date min = d;
	int flag = 1;
	
	if (*this < d) {
		max = d;
		min = *this;
		flag = -1;
	}
	
	int count = 0;
	
	while (min != max) {
		++min;
		++count;
	}
	
	return count * flag;
}

这段代码的逻辑是:

cpp 复制代码
1. 先假设当前对象是较大日期;
2. 如果当前对象小于 d,就交换 max 和 min;
3. 让 min 不断前置 ++;
4. 每加一天,count 加 1;
5. min 等于 max 停止;
6. 最后乘以 flag 修正正负号。

十、为什么使用前置++?

在循环中:

cpp 复制代码
++min;

优先使用前置++,而不是后置++:

cpp 复制代码
min++;

原因是后置 ++ 需要保存旧值,会产生临时对象。

而这里不需要旧值,只需要让日期加一天。

所以使用前置 ++ 更合适。

前面也提到,后置操作因为涉及临时对象的拷贝,性能低于前置操作,因此在不需要旧值时优先使用前置形式。

十一、完整示例片段

这里只展示和本篇相关的核心函数:

cpp 复制代码
class Date {
	public:
		Date& operator<(const Date& d) const;
		Date& operator!=(xonst Date& d) const;
		
		Date& operator+=(int day);
		Date& operator-=(int day);
		
		Date& operator++() {
			return *this += 1;
		} 
		
		Date operator++(int) {
			Date tmp = *this;
			*this += 1;
			return tmp;
		}
		
		Date& operator--() {
			return *this -= 1;
		}
		
		Date operator--(int) {
			Date tmp = *this;
			*this -= 1;
			return tmp;
		}
		
		int operator-(const Date& d) const {
			Date max = *this;
			Date min = d;
			int flag = 1;
			
			if (*this < d) {
				max = d;
				min = *this;
				flag = -1;
			}
			
			int count = 0;
			
			while (min != max) {
				++min;
				++count;
			}
			
			return count * flag;
		} 
		
		
	private:
		int _year;
		int _month;
		int _day; 
};

十二、小结

本篇主要学习了日期类中的前置后置 ++/-- 和日期减日期。

需要记住:

  1. 前置 ++ 是先加,在返回当前对象;
  2. 后置 ++ 是先保存旧值,再加,返回旧值;
  3. 后置 ++ 通过 int 占位参数和前置 ++ 区分;
  4. 前置 ++ 返回当前对象的引用;
  5. 后置 ++ 返回旧值,不能返回局部对象引用;
  6. -- 的实现和 ++ 类似,只是方向相反;
  7. 日期减日期表示两个日期相差多少天;
  8. 直接借位计算较复杂,可以采用"小日期加和到大日期"的方式;
  9. 使用 flag 处理结果正负;
  10. 不需要旧值时,优先使用前置 ++,减少临时拷贝。

日期类是练习运算符重载的经典案例。通过这些运算符的实现,可以更好的理解值返回、引用返回、临时对象、代码复用以及边界处理。

相关推荐
计算机安禾9 小时前
【c++面向对象编程】第40篇:单例模式(Singleton)的多种C++实现
开发语言·c++·单例模式
一个不知名程序员www9 小时前
算法学习入门---算法题DAY1
c++·算法
桀人9 小时前
C++——内存管理——new和delete的超详细解析
开发语言·c++
Shadow(⊙o⊙)9 小时前
Shell进程替换,自定义Shell解释器——字符串库函数灵活操作!
linux·运维·服务器·开发语言·c++·学习
_F_y9 小时前
树形 DP 从入门到进阶:普通树形DP、树形背包、换根DP
c++·动态规划
Hua-Jay10 小时前
OpenCV联合C++/Qt 学习笔记(二十三)----图像校正及单目位姿估计
c++·笔记·qt·opencv·学习·计算机视觉
charlie11451419110 小时前
现代C++特性指南(4)——完美转发与移动语义实战
开发语言·c++·现代c++
小白|10 小时前
cann-learning-hub:昇腾CANN社区学习中心完全指南
java·c++·算法
mirror_zAI10 小时前
C++ 仿 QQ 聊天室项目:Qt 客户端 + epoll 服务端 + Reactor 架构(含源码)
c++·qt·架构