当前位置: 首页> 娱乐> 明星 > 【C++】——运算符重载之日期类的实现

【C++】——运算符重载之日期类的实现

时间:2025/9/26 12:51:41来源:https://blog.csdn.net/2301_77112794/article/details/140607740 浏览次数:0次

目录

  • 前言
  • 日期类的实现
    • 要点
    • 日期检查
    • 日期的大小比较
    • 获取当月的天数
    • 日期+=天数
    • 日期-=天数
    • 前置++和后置++
    • 日期减日期
  • 完整代码
    • Date.h
    • Date.cpp
    • test.cpp

请添加图片描述

前言

  前面我们说了类的六个默认成员函数:大家可以自行查看前面的内容:构造和析构函数、类和对象的默认成员函数下。
  在讲默认成员函数下时我们有提过运算符重载函数,下面我们具体拓展一下各个符号的重载,并用其实现一个日期类。当然,它们使用的规则,可以应用到其他所有类中实现。

注意:运算符重载和函数重载没有直接的关系。
函数重载是让函数名相同,参数不同的函数存在。
运算符重载是让自定义类型可以使用运算符,并且控制运算符的行为,增强可读性
但是多个同一运算符重载可构成函数重载

日期类的实现

要点

  我们想要完成日期类时我们首先要知道它要干什么,它想要实现什么东西,下面我们来一一列举一下:

  1. 日期的大小比较
  2. 计算两个日期间隔的天数
  3. 日期+天数
  4. 日期-天数
  5. 前置++和后置++

日期检查

  当我们在输入日期时,可能会将日期输错,此时我们可以写一个日期检查的函数,用来检查判断我们输入的日期是否正确

bool Date::CheakDay()
{if (_year <= 0 || _month <= 0 || _month > 12 || _day<0 || _day>GetMonthDay(_year, _month))return false;elsereturn true;
}

日期的大小比较

  我们将需要的类和所涉及的成员函数及变量一一列出:

class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){}bool operator<(const Date& d1);bool operator<=(const Date& d1);bool operator>(const Date& d1);bool operator>=(const Date& d1);bool operator==(const Date& d1);bool operator!=(const Date& d1);
private:int _year;int _month;int _day;
};

  下面,我们将这六个比较大小的函数一一实现。
  首先我们来实现小于的运算符重载,我们根据年月日依次比较得出大小:

bool Date::operator<(const Date& d)//加const防止d被改变
{if (_year < d._year)return true;//年小就小else if (_year == d._year)//年相同就比月{if (_month < d._month)return true;else if (_month == d._month)//月再相同就比日return (_day < d._day);}return false;
}

我们来测试一下:
在这里插入图片描述
  我们发现,如果我们给d2加了const,我们只能进行d1<d2的比较,而不能反过来写,这是涉及到const权限的问题,d2是const Date类型,而成员函数中隐含的this指针是Date const 类型,所以我们给成员函数加上const关键字进行修饰,使得this指针的类型变为const Date* const类型,使其能进行匹配,为了方便,我们将不用改变日期的函数都用const进行修饰
在这里插入图片描述
  这样可成功实现。
  下面我们再来实现最简单的判断日期是否相等:

bool Date::operator==(const Date& d) const
{return _year == d._year&& _month == d._month&& _day == d._day;
}

  运行测试比较简单,后期大家自行去实现。
  下面继续来实现剩余四种判断,我们已经写了小于和等于的运行规则,剩下四个我们可以直接覆用小于和等于的规则即可,就不用单独再去实现了,如下所示:

bool Date::operator<=(const Date& d) const
{return *this < d || *this == d;
}
bool Date::operator>(const Date& d) const
{return !(*this <= d);
}
bool Date::operator>=(const Date& d) const
{return !(*this < d);
}
bool Date::operator!=(const Date& d) const
{return !(*this == d);
}

测试大家自行实现即可。

获取当月的天数

  当我们要对日期进行加减时,要获取当月的天数是必不可少的,那我们就可以写一个函数,将其放到类中,使其变为内联函数,这样我们在使用时就能减少一些调用函数的损耗。
获取当月天数的函数代码如下:

int GetMonthDay(int year, int month)
{assert(month > 0 && month < 13);static int MonthDayArr[] = { 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;elsereturn MonthDayArr[month];
}

  我们发现,一个简单的获取当前月份天数的函数,其实藏着一些细节,一个就是assert断言,如果月份不在1~12这个范围内就会报错,防止输入错误。第二个就是创建数组的时候我们用了一个static关键字,使这个函数的生命周期延长,将其放在了静态区,不用每调用一次函数就要创建一次数组,这样减少了内存消耗。第三个就是创建数组的第一个元素用0代替,可以让数组下标与月份一一对应,直接将月份作为下标输出即可。

日期+=天数

  我们想要日期+=天数时,我们都会将其直接加到日(_day)上面,然后判断_day的天数是否超过了本月的天数,当超过时,我们就需要用_day减去当前月的天数,然后让月++,注意要判断是否会延伸到下一年,相信大家也都会,我就不再赘述。

Date& Date::operator+=(int n)
{_day += n;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13){_month = 1;++_year;}}return *this;
}

  我们使用了引用返回,减少了消耗,同时使用了前置++,同样也为了减少消耗,这点后面也会讲到。

注意:我们还要区分日期+=天数和日期+天数的区别,一个是会实际改变d的值,而日期+天数中d的值实际上是没有发生变化的,这点需要清楚。懂了这些区别,我们也就可以继续使用覆用来实现日期+天数:

Date Date::operator+(int n)
{Date tmp = *this;tmp += n;return tmp;
}

  这里我们使用值返回,是因为tmp出了函数作用域会被销毁,则不能用引用返回,具体可看上节所说的。我们用了tmp拷贝了*this,用tmp进行+=,这样返回加之后的值,但是 *this没有改变,达到了我们想要的目的。

日期-=天数

  对于日期-=天数和日期+=天数的思路是一样的,都是按照常规去算即可,代码如下:

Date& Date::operator-=(int n)
{_day -= n;while (_day <= 0){_month--;if (_month == 0){_month = 12;_year--;}_day += GetMonthDay(_year, _month);}return *this;
}

  同样我们用了引用返回,减少拷贝的消耗。
  日期-天数也是同样的做法:

Date Date::operator-(int n)
{Date tmp = *this;tmp -= n;return tmp;
}

前置++和后置++

  我们要清楚的是前置++和后置++的区别是什么:

  • 前置++:先加后使用,返回+1之后的结果。
  • 后置++:先使用后加,返回+1之前的结果。

  我们发现,如果直接写运算符重载函数,它们两都可以被写成:

Date operator++();

  因此为了区分这两着,我们在后置++的括号里面加了一个int,即:

Date operator++(int);

  虽然说括号里面有个int类型的形参,但是在调用函数时这个参数是不用传递的,编译器会自动传递,只是为了和前置++做出区分。
  明白了这个代码写出来也就很简单了,代码如下:

Date& Date::operator++()//前置++
{_day += 1;return *this;
}
Date& Date::operator--()//前置--
{_day -= 1;return *this;
}
Date Date::operator++(int)//后置++
{Date tmp = *this;*this += 1;return tmp;
}
Date Date::operator--(int)//后置--
{Date tmp = *this;*this -= 1;return tmp;
}

  我们可以发现,前置运算符都是用引用返回,而后置运算符都是用值返回,值返回会增加拷贝次数,所以为了减少消耗,提高效率,我们更推荐使用前置运算符。

日期减日期

  在实现日期减日期时,我们首先要知道他们是如何相减得到的。
  按照我们一般思路就是找到两个日期正常相减,但是我们可以直接用一个循环来实现,具体见代码:

int Date::operator-(const Date& d) const
{int flag = 1;int sum = 0;Date max = *this;Date min = d;if (d > *this){max = d;min = *this;flag = -1;}while (max != min){++sum;--max;}return flag * sum;
}

  这也是一个很巧妙的代码,用了max和min,这样可以保证一直是max–。又多用了一个flag,如果日期1-日期2中,日期1比较小,可以使得得出的结果为负数,一目了然。

完整代码

  有关日期类的实现已经全部完成了,下面是完整代码:

Date.h

#include<assert.h>
#include<iostream>
using namespace std;class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){}int GetMonthDay(int year, int month){assert(month > 0 && month < 13);static int MonthDayArr[] = { 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;elsereturn MonthDayArr[month];}void Print(){cout << _year << "年" << _month << "月" << _day << "日" << endl;}void Insert(){cin >> _year;cin >> _month;cin >> _day;if (!CheakDay())cout << "输入错误,请重新输入" << endl;}bool CheakDay();bool operator<(const Date& d)const;bool operator<=(const Date& d)const;bool operator>(const Date& d)const;bool operator>=(const Date& d)const;bool operator==(const Date& d)const;bool operator!=(const Date& d)const;Date& operator+=(int n);Date operator+(int n);Date& operator-=(int n);Date operator-(int n);Date& operator++();Date& operator--();Date operator++(int);Date operator--(int);int operator-(const Date& d)const;
private:int _year;int _month;int _day;
};

Date.cpp

#include"Date.h"bool Date::CheakDay()
{if (_year <= 0 || _month <= 0 || _month > 12 || _day<0 || _day>GetMonthDay(_year, _month))return false;elsereturn true;
}bool Date::operator<(const Date& d) const
{if (_year < d._year)return true;else if (_year == d._year){if (_month < d._month)return true;else if (_month == d._month)return (_day < d._day);}return false;
}
bool Date::operator<=(const Date& d) const
{return *this < d || *this == d;
}
bool Date::operator>(const Date& d) const
{return !(*this <= d);
}
bool Date::operator>=(const Date& d) const
{return !(*this < d);
}
bool Date::operator==(const Date& d) const
{return _year == d._year&& _month == d._month&& _day == d._day;
}
bool Date::operator!=(const Date& d) const
{return !(*this == d);
}Date& Date::operator+=(int n)
{_day += n;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13){_month = 1;++_year;}}return *this;
}
Date Date::operator+(int n)
{Date tmp = *this;tmp += n;return tmp;
}Date& Date::operator-=(int n)
{_day -= n;while (_day <= 0){_month--;if (_month == 0){_month = 12;_year--;}_day += GetMonthDay(_year, _month);}return *this;
}
Date Date::operator-(int n)
{Date tmp = *this;tmp -= n;return tmp;
}
Date& Date::operator++()//前置++
{_day += 1;return *this;
}
Date& Date::operator--()//前置--
{_day -= 1;return *this;
}
Date Date::operator++(int)//后置++
{Date tmp = *this;*this += 1;return tmp;
}
Date Date::operator--(int)//后置--
{Date tmp = *this;*this -= 1;return tmp;
}int Date::operator-(const Date& d) const
{int flag = 1;int sum = 0;Date max = *this;Date min = d;if (d > *this){max = d;min = *this;flag = -1;}while (max != min){++sum;--max;}return flag * sum;
}

test.cpp

这属于调试代码,大家可以自行输入调试。

#include"Date.h"int main()
{Date d1(2024, 7, 24);Date d2(2024, 7, 22);cout << (d1 < d2) << endl;cout << (d2 == d1) << endl;cout << (d2 != d1) << endl;cout << (d2 > d1) << endl;cout << (d2 <= d1) << endl;cout << (d2 >= d1) << endl;d2 += 70;d2.Print();Date d3(2030, 7, 1);cout << (d3 - d1) << endl;return 0;
}

  今天的内容到此结束啦,感谢大家观看,如果大家喜欢,希望大家一键三连支持一下,如有表述不正确,也欢迎大家批评指正。

请添加图片描述

关键字:【C++】——运算符重载之日期类的实现

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: