C++学习笔记21:日期类加减天数

目录

一、日期类中的哪些运算有意义?

二、日期类基本结构

三、获取某年某月的天数

[四、实现 Date += int](#四、实现 Date += int)

[五、为什么 += 返回引用?](#五、为什么 += 返回引用?)

[六、实现 Date + int](#六、实现 Date + int)

[七、+ 和 += 的区别](#七、+ 和 += 的区别)

[八、实现 Date -= int](#八、实现 Date -= int)

[九、实现 Date - int](#九、实现 Date - int)

十、处理负数情况

十一、完整代码示例

十二、小结


一、日期类中的哪些运算有意义?

在日期类中,不是所有的运算都有实际意义。

比如:

cpp 复制代码
日期 + 日期
日期 * 日期
日期 / 日期

这些运算通常都没有明确意义。

但是下面这些运算是有意义的:

cpp 复制代码
日期 + 天数
日期 - 天数
日期 += 天数
日期 -= 天数

例如:

cpp 复制代码
2024-5-1 + 10天 = 2024-5-11
2024-5-1 - 10天 = 2024-4-21

所以日期类中可以重载 +、+=、-、-=这些运算符。


二、日期类基本结构

先准备一个基本的 Date 类:

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; 
};

日期加减天数,最重要的是知道每个月有多少天。


三、获取某年某月的天数

因为不同月份天数不同,2 月还要考虑闰年,所以可以写一个 GetMonthDay 函数:

cpp 复制代码
int GetMonthDay(int year, int month) {
	static int monthDayArray[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 monthDayArray[month];	
}

这里 static 数组保存每个月的天数,避免每次调用函数都重新创建数组。

闰年判断规则是:

cpp 复制代码
四年一闰,百年不闰,四百年再闰

也就是:

cpp 复制代码
(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)

四、实现 Date += int

+= 的含义是:在当前日期基础上加上指定天数,并且修改当前对象。

例如:

cpp 复制代码
Date d(2024, 5, 1);
d += 10;

执行后,d 本身变成:

cpp 复制代码
2024-5-11

实现思路:

cpp 复制代码
1. 先把天数直接加到 _day 上;
2. 如果 _day 超过当前月份天数,就减去当前月份天数;
3. 月份加 1;
4. 如果月份超过 12,就年份加 1,月份变成 1;
5. 循环处理,直到日期合法。

代码:

cpp 复制代码
Date& operator+=(int day) {
	_day += day;
			
	while (_day > GetMonthDay(_year, _month)) {
		_day -= GetMonthDay(_year, _month);
		_month++;
				
		if (_month == 13) {
			_year++;
			_month = 1;
		}
	}
			
	return *this;
}

五、为什么 += 返回引用?

+= 操作会改变原对象。

例如:

cpp 复制代码
d += 10;

本质上是修改 d 自己。

所以返回当前对象是合理的。

cpp 复制代码
Date& operator+=(int day) {
    // 修改当前对象
    return *this;
}

这里返回的是:

cpp 复制代码
*this

表示当前对象本身。

返回引用的好处是:

cpp 复制代码
1. 避免拷贝;
2. 支持连续操作;
3. 符合内置类型运算习惯。

六、实现 Date + int

  • 和 += 不一样。

  • 的含义是返回一个新的日期类对象,不改变原对象。

例如:

cpp 复制代码
Date d1(2024, 5, 1);
Date d2 = d1 + 10;

执行后:

cpp 复制代码
d1 仍然是 2024-5-1
d2 是 2024-5-11

所以 operator+ 可以复用 operator+=:

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

这里先拷贝一份当前对象:

cpp 复制代码
Date tmp(*this);

然后对 tmp 加天数:

cpp 复制代码
tmp += day;

最后返回 tmp。

这样就不会修改原变量。


七、+ 和 += 的区别

二者区别很重要:

运算符 是否修改当前对象 返回值
+ 不修改 返回新对象
+= 修改 返回当前对象引用

八、实现 Date -= int

日期见天数和提起加天数很类似,只是方向相反。

例如:

cpp 复制代码
Date d(2024, 5, 1);
d -= 10;

结果应该是:

cpp 复制代码
2024-4-21

实现思路:

cpp 复制代码
1. 让 _day 减去 day
2. 如果 _day 小于等于 0,说明需要向上一个月借天数;
3. 月份减 1;
4. 如果月份变成 0,年份减 1,月份变成12;
5. 坝上一个月的天数加到 _day 上;
6. 循环处理,直到日期合法。

代码:

cpp 复制代码
Date& operator-=(int day) {
	_day -= day;
			
	while (_day <= 0) {
		_month--;
				
		if (_month == 0) {
			_year--;
			_month = 12;
		}
				
		_day += GetMonthDay(_year, _month);
	}
			
	return *this;
}

九、实现 Date - int

Date - int 和 Date + int 类似,也是不改变原对象,而是返回一个新对象。

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

例如:

cpp 复制代码
Date d1(2024, 5, 1);
Date d2 = d1 - 10;

执行后:

cpp 复制代码
d1 仍然是 2024-5-1
d2 是 2024-4-21

十、处理负数情况

如果传入的是负数,也可以转换成相反操作。

例如:

cpp 复制代码
d + (-10)

可以理解为:

cpp 复制代码
d - 10

所以可以在 operator+= 里处理:

cpp 复制代码
Date& operator+=(int day) {
    if (day < 0) {
        return *this -= -day;
    }
    
	_day += day;
			
	while (_day > GetMonthDay(_year, _month)) {
		_day -= GetMonthDay(_year, _month);
		_month++;
				
		if (_month == 13) {
			_year++;
			_month = 1;
		}
	}
			
	return *this;
}

同理,-=也可以处理负数。


十一、完整代码示例

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;
		}
		
		int GetMonthDay(int year, int month) {
			static int monthDayArray[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 monthDayArray[month];	
		} 
		
		Date& operator+=(int day) {
			if (day < 0) {
				return *this -= -day;
			}
			
			_day += day;
			
			while (_day > GetMonthDay(_year, _month)) {
				_day -= GetMonthDay(_year, _month);
				_month++;
				
				if (_month == 13) {
					_year++;
					_month = 1;
				}
			}
			
			return *this;
		}
		
		Date operator+(int day) {
			Date tmp(*this);
			tmp += day;
			return tmp;
		}
		
		Date& operator-=(int day) {
			if (day < 0) {
				return *this += -day;
			}
			
			_day -= day;
			
			while (_day <= 0) {
				_month--;
				
				if (_month == 0) {
					_year--;
					_month = 12;
				}
				
				_day += GetMonthDay(_year, _month);
			}
			
			return *this;
		}
		
		Date operator-(int day) {
			Date tmp(*this);
			tmp -= day;
			return tmp;
		}
		
	private:
		int _year;
		int _month;
		int _day; 
};

int main() {
	Date d1(2024, 5, 1);
	
	Date d2 = d1 + 10;
	Date d3 = d1 - 10;
	
	d1.Print();
	d2.Print();
	d3.Print();
	
	d1 += 100;
	d1.Print();
	
	d1 -= 100;
	d1.Print();
	
	return 0;
}

十二、小结

本篇主要学习了日期类加减天数。

需要记住:

  1. 日期加天数有意义,日期加日期通常没有意义;
  2. Date + int 返回新对象;
  3. Date += int 修改当前对象,返回当前对象;
  4. Date - int 返回新对象;
  5. Date -= int 修改当前对象,返回当前对象;
    • 可以复用 +=;
    • 可以复用 -=;
  6. 跨月时要减去当前月份天数;
  7. 跨年时要处理 12 到 1 月,或者 1 月 到 12 月;
  8. 加负数可以转换成减正数,减负数可以转换成加正数。

日期类加减天数是运算符重载中的很典型的练习,既能练习 operator 的写法,也能训练边界处理和代码复用能力。

相关推荐
努力努力再努力wz1 小时前
【QT入门系列】QWidget 六大常用属性详解:windowOpacity、cursor、font、focus、toolTip 与 styleSheet
android·开发语言·数据结构·c++·qt·mysql·算法
少司府1 小时前
Tools相关:深入浅出学Git
大数据·c++·git·gitee·github·仓库·分支
神仙别闹1 小时前
基于MFC(C++)实现(界面)学委作业管理系统
开发语言·c++·mfc
艾莉丝努力练剑1 小时前
【Linux网络】Linux 网络编程:HTTP(三)HTTP 协议原理
linux·运维·服务器·网络·c++·http
字节高级特工1 小时前
C++11(一) 革新:右值引用与移动语义
java·开发语言·c++·人工智能·后端
叶之香1 小时前
一次 Kingston U 盘重定向中获取 Device Descriptor 超时问题排查
c++·windows·visual studio
UestcXiye1 小时前
GoogleTest 使用指南 | 单元覆盖率分析
c++·单元测试·googletest
王老师青少年编程1 小时前
csp信奥赛C++高频考点专项训练之前缀和&差分 --【一维前缀和】:“非常男女”计划
c++·前缀和·csp·高频考点·信奥赛·“非常男女”计划
故事和你911 小时前
洛谷-【图论2-4】连通性问题2
开发语言·数据结构·c++·算法·动态规划·图论