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 的写法,也能训练边界处理和代码复用能力。

相关推荐
WWW65261 小时前
代码随想录 打卡第五十四天
数据结构·c++·算法
redaijufeng1 小时前
我在C++中深入理解了继承,收获颇丰
java·c++·算法
.千余1 小时前
【C++】C++继承入门(上):继承语法与基本特性详解
开发语言·c++·笔记·学习·其他
哎呦,帅小伙哦2 小时前
一个通用的异步任务提交器
c++
闻道且行之2 小时前
Hair Segmentation:MediaPipe 头发分割模块 CMake 独立编译
c++·人工智能·深度学习·神经网络·opencv·计算机视觉
Irissgwe2 小时前
C++ STL 详解:list 的介绍使用与模拟实现
开发语言·c++·stl·list
我能坚持多久2 小时前
C++继承详解
开发语言·c++
Brilliantwxx2 小时前
【C++】 手撕哈希表:封装 unordered_set和unordered_map
c++·哈希算法·散列表
Rookie Linux2 小时前
使用Qt6 QML以及第三方库FluentUI、PCapPlusPlus开发一个自定义抓包软件
网络·c++·qt·cmake·qml
江屿风2 小时前
C++图论基础拓扑排序算法流食般投喂
开发语言·c++·笔记·算法·排序算法