目录
[四、实现 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;
}
十二、小结
本篇主要学习了日期类加减天数。
需要记住:
- 日期加天数有意义,日期加日期通常没有意义;
- Date + int 返回新对象;
- Date += int 修改当前对象,返回当前对象;
- Date - int 返回新对象;
- Date -= int 修改当前对象,返回当前对象;
-
- 可以复用 +=;
-
- 可以复用 -=;
- 跨月时要减去当前月份天数;
- 跨年时要处理 12 到 1 月,或者 1 月 到 12 月;
- 加负数可以转换成减正数,减负数可以转换成加正数。
日期类加减天数是运算符重载中的很典型的练习,既能练习 operator 的写法,也能训练边界处理和代码复用能力。