C++ 运算符重载实战|日期类实现日期加减天数、两日期求间隔天数

一、全部源码展示

复制代码
#include<iostream>
using namespace std;

class Date
{
public:
    // 构造函数
    Date(int year = 1900, int month = 1, int day = 1)
        :_year(year), _month(month), _day(day)
    {}

    // 打印日期
    void Print() const
    {
        cout << _year << "年" << _month << "月" << _day << "日" << endl;
    }

    // 获取当月天数,静态工具函数
    static int GetMonthDay(int year, int month)
    {
        static int monthDays[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
        // 闰年判断
        if (month == 2)
        {
            if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
                return 29;
        }
        return monthDays[month];
    }

    // 复合赋值 += 日期加天数(修改自身)
    Date& operator+=(int day);
    // 复合赋值 -= 日期减天数(修改自身)
    Date& operator-=(int day);

    // 日期 + 天数,返回新日期,不修改自身
    Date operator+(int day) const;
    // 日期 - 天数,返回新日期,不修改自身
    Date operator-(int day) const;

    // 两个日期相减,返回相差天数
    int operator-(const Date& d) const;

private:
    int _year;
    int _month;
    int _day;

    // 私有工具:日期向前减一天
    void SubOneDay();
    // 私有工具:日期向后加一天
    void AddOneDay();
};

// += 重载:当前日期增加day天
Date& 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;
}

// -= 重载:当前日期减少day天
Date& Date::operator-=(int day)
{
    if (day < 0)
    {
        return *this += -day;
    }
    for (int i = 0; i < day; i++)
    {
        SubOneDay();
    }
    return *this;
}

// 日期 + 天数,生成新对象不改变原对象
Date Date::operator+(int day) const
{
    Date tmp = *this;
    tmp += day;
    return tmp;
}

// 日期 - 天数,生成新对象不改变原对象
Date Date::operator-(int day) const
{
    Date tmp = *this;
    tmp -= day;
    return tmp;
}

// 私有:往前推一天
void Date::SubOneDay()
{
    _day--;
    if (_day == 0)
    {
        _month--;
        if (_month == 0)
        {
            _year--;
            _month = 12;
        }
        _day = GetMonthDay(_year, _month);
    }
}

// 私有:往后推一天
void Date::AddOneDay()
{
    _day++;
    if (_day > GetMonthDay(_year, _month))
    {
        _day = 1;
        _month++;
        if (_month == 13)
        {
            _year++;
            _month = 1;
        }
    }
}

// 两个日期相减,返回相差总天数
int Date::operator-(const Date& d) const
{
    Date maxDate = *this;
    Date minDate = d;
    int count = 0;
    bool flag = false;
    if (*this < d)
    {
        maxDate = d;
        minDate = *this;
        flag = true;
    }
    while (!(maxDate == minDate))
    {
        minDate.AddOneDay();
        count++;
    }
    return flag ? -count : count;
}

// 补充==、<比较运算符(日期相减依赖)
bool operator==(const Date& d1, const Date& d2)
{
    return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}

bool operator<(const Date& d1, const Date& d2)
{
    if (d1._year < d2._year)
        return true;
    if (d1._year == d2._year && d1._month < d2._month)
        return true;
    if (d1._year == d2._year && d1._month == d2._month && d1._day < d2._day)
        return true;
    return false;
}

// 测试主函数
int main()
{
    // 1. 日期加天数测试:2026.3.1 + 1000天
    Date d1(2026, 3, 1);
    Date resAdd = d1 + 1000;
    cout << "2026年3月1日加1000天:";
    resAdd.Print();

    // 2. 日期减天数测试
    Date d2(2028, 11, 25);
    Date resSub = d2 - 1000;
    cout << "2028年11月25日减1000天:";
    resSub.Print();

    // 3. 两个日期相减,求间隔天数
    Date start(2026, 3, 1);
    Date end(2028, 11, 25);
    int gap = end - start;
    cout << "两个日期相差天数:" << gap << "天" << endl;

    return 0;
}

二、功能整体说明

  1. operator+ / operator-:日期 ± 天数,返回全新日期对象,不修改原日期
  2. operator+= / operator-=:复合赋值,直接修改当前日期自身,支持链式调用;
  3. operator-(两个Date对象):重载减法,计算两个日期之间相差的总天数,支持正负;
  4. 内置静态工具GetMonthDay自动区分平闰年,正确获取 2 月天数;
  5. 封装私有AddOneDay/SubOneDay实现单天进退位,简化上层逻辑。

三、核心运算符重载原理拆解

1. 复合赋值 += /-=(修改自身,返回引用)

复合赋值运算符语义是改变调用对象本身 ,所以返回Date&引用,支持连续运算如d += 100 += 50。 逻辑:

  • +=:天数累加后循环判断是否超过当月最大天数,超则进月、进年;
  • -=:循环逐天向前递减,遇到月初自动退至上一年 / 上月。
2. 普通运算符 + /-(不修改原对象,返回临时拷贝)

数学上 日期 + 天数 不会改变原本日期,因此实现逻辑:

  1. 拷贝一份当前日期临时对象 tmp;
  2. 对 tmp 使用+=/-=完成计算;
  3. 返回临时对象,原对象保持不变。
3. 两个日期相减 operator-(Date d)

重载两个 Date 对象相减,用于计算间隔天数:

  1. 比较两个日期大小,区分最大、最小日期;
  2. 最小日期逐天向后累加,直到与大日期相等,统计累加次数;
  3. 如果传入顺序是大日期减小日期,返回正数,反之返回负数。 该功能依赖==相等重载、<小于比较重载辅助判断。
4. 闰年与月份天数处理

静态函数GetMonthDay使用 static 数组存储平年每月天数,仅初始化一次提升性能; 闰年规则严格遵循:四年一闰、百年不闰、四百年再闰,仅 2 月特殊返回 29 天。

四、测试用例运行结果

main 函数内置三组测试:

  1. 2026 年 3 月 1 日 + 1000 天,输出 2028 年 11 月 25 日;

  2. 2028 年 11 月 25 日 - 1000 天,还原 2026 年 3 月 1 日;

  3. 两个日期相减直接输出间隔 1000 天。 运行输出:

    复制代码
    2026年3月1日加1000天:2028年11月25日
    2028年11月25日减1000天:2026年3月1日
    两个日期相差天数:1000天