广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >【C++深入浅出】日期类的实现
  • 295
分享到

【C++深入浅出】日期类的实现

c++类和对象日期类运算符重载 2023-09-18 15:09:43 295人浏览 安东尼
摘要

目录 一. 前言  二. 日期类的框架 三. 日期类的实现 3.1 构造函数 3.2 析构函数 3.3 赋值运算符重载 3.4 关系运算符重载 3.5 日期 +/- 天数 3.6 自增与自减运算符重载 3.7 日期 - 日期 四. 完整


目录

一. 前言 

二. 日期类的框架

三. 日期类的实现

3.1 构造函数

3.2 析构函数

3.3 赋值运算符重载

3.4 关系运算符重载

3.5 日期 +/- 天数

3.6 自增与自减运算符重载

3.7 日期 - 日期

四. 完整代码 


一. 前言 

        通过前面两期类和对象的学习,我们已经对c++的类有了一定的了解。本期我们的目标是实现一个完整的日期类,通过实现日期类的构造函数、运算符重载等等内容,加深对前面知识的理解。

        实现了日期类之后,我们就相当于自己实现了一个网上的日期计算器,如下所示

         上面的两项功能,都是通过我们接下来要进行的运算符重载实现的。

二. 日期类的框架

        以下是我们本期实现的日期类的基本框架

class Date{public:// 全缺省的构造函数Date(int year = 2023, int month = 1, int day = 1);// 拷贝构造函数Date(const Date& d);// 赋值运算符重载Date& operator=(const Date& d);// 析构函数~Date() {};// +、=等算数运算符重载Date& operator+=(int day); //日期+=天数Date operator+(int day); //日期+天数Date& operator-=(int day); //日期-=天数Date operator-(int day); //日期-天数// 日期-日期 返回天数,即日期差int operator-(const Date& d);// 自增、自减运算符重载Date& operator++(); //前置++Date operator++(int); //后置++Date operator--(int); //后置--Date& operator--(); //前置--// >、<、==等关系运算符重载bool operator>(const Date& d); bool operator==(const Date& d); bool operator >= (const Date& d);bool operator < (const Date& d);bool operator <= (const Date& d);bool operator != (const Date& d);//打印数据void Print();private:int _year; //年int _month; //月int _day; //日};

三. 日期类的实现

3.1 构造函数

        构造函数的目的是初始化类对象,这里我们只需要实现两种构造函数即可。一种是全缺省的构造函数,使用全缺省的构造函数可以让类对象构造时传参更加灵活;而另一种则是拷贝构造函数

        全缺省的构造函数

        很简单,我们只需要判断传入的参数是否符合生活中日期的规则,如果符合则正常进行初始化,反之则程序退出。规则大致如下

日期规则

1、月份必须在1月到12月之间。例如0月和13月是非法的

2、日份必须在当前月的天数范围内。例如1月32日,4月31日是非法的

        由于每个月的天数不同,尤其是2月,还有闰年平年之分,故我们可以先写个函数用来获取当前月的天数。这个函数不仅可以用在日份的判断,在之后也会经常用到。

// 获取某年某月的天数int GetMonthDay(int year, int month){    //用一个数组表示平年每月的天数,下标表示月份int MouthDayArray[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)) //判断闰年{MouthDayArray[2]++; //是闰年,2月份天数+1}return MouthDayArray[month]; //返回当前月天数}

        有了上面的函数, 再根据之前的规则,我们很容易就可以写出构造函数

// 全缺省的构造函数Date(int year = 2023, int month = 1, int day = 1){if ( month < 1 || month > 12 || day < 1 || day > GetMonthDay(year, month)){cout << "日期非法" << endl;exit(-1);}_year = year;_month = month;_day = day;}

        拷贝构造函数

        拷贝构造函数就更简单了,拷贝构造函数是用已存在的对象初始化新对象,故不需要考虑日期是否合法,直接拷贝即可,如下:

// 拷贝构造函数, d2(d1)Date(const Date& d) //加const避免d被意外修改,使用引用传递是为了提高效率{_year = d._year;_month = d._month;_day = d._day;}

3.2 析构函数

        由于日期类不涉及动态内存管理,因此使用编译器自动生成的析构函数即可,不需要显式进行实现。 

3.3 赋值运算符重载

        同理,由于日期类不涉及动态内存管理,因此只要进行普通的浅拷贝即可,编译器默认生成的赋值运算符重载函数即可完成要求。

//赋值运算符重载,不需要显式进行实现,这里使用编译器默认生成的即可Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this; //返回当前对象的引用为了实现链式访问}

3.4 关系运算符重载

        关系运算符有><>=<===以及!=,我们先来实现">"运算符。

        我们要如何判断一个日期大于另一个日期呢?很简单,先比较年,年相等则比较月,月相等则比较日,直到比出结果。代码如下:

// >运算符重载bool operator>(const Date& d){if (_year > d._year) //比较年{return true; }else if (_year == d._year && _month > d._month) //年相等比较月{return true;}else if (_year == d._year && _month == d._month && _day > d._day) //年月都相等比较日{return true;}else //前面的条件都不符合,说明日期比较小,返回false{return false;}}

        接下来是"=="运算符,这就简单啦,看看年月日是否都相等即可 

// ==运算符重载bool operator==(const Date& d){    // 逻辑与,下面的条件都符合才返回true,否则为falsereturn (_year == d._year) && (_month == d._month) && (_day == d._day);}

        然后是"<"运算符,我知道我知道,把上面">"运算符的逻辑都反过来再敲一遍就好啦 

        这种方法固然可以,但未免会显得过于冗余。实际上,我们已经实现了">"运算符和"=="运算符重载,那"<"不就是既不大于也不等于嘛,我们复用一下之前的重载函数即可,如下

// <运算符重载bool operator<(const Date& d){    //*this表示当前对象return !((*this == d) || (*this > d)); //逻辑非之后表示既不大于也不等于}

        通过复用的方法,剩下的"<="、">="和"!="我们也可以很轻松的写出来,如下:

// >=运算符重载bool operator>=(const Date& d){return !(*this < d); //复用<运算符}// <=运算符重载bool operator<=(const Date& d){return !(*this > d); //复用>运算符}// !=运算符重载bool operator!=(const Date& d){return !(*this == d); //复用==运算符}

小贴士:实现类中成员函数时,并不意味着每个都要将其逻辑完整地写出,有些函数之间可以相互复用,简化代码。例如上面我们只需实现">"号和"=="号的重载函数,其余的函数直接复用即可。

3.5 日期 +/- 天数

        接下来我们来实现日期计算器的第一个功能:推算几天后的日期。通过重载"+/-"号运算符我们可以实现日期 +/- 指定天数

         日期 + 指定天数

         首先,我们要知道,日期的进位规则和我们的十进制不一样。每个月的天数都不同,当超过本月的天数,月份都要进1,并且每过12个月年份都要进1。故我们需要用到之前实现的获取本月天数的函数,用来判断是否需要进位。

        例如,求在12月3号的基础上100天后是几月几号?计算过程如下

 

        下面给出示例代码(初版): 

// 日期+=天数(初版)Date& operator+=(int day){_day += day; //先将天数全部加到_day上        //下面开始进行进位while (_day > GetMonthDay(_year, _month)) //当_day大于本月的天数说明还需要进行进位,继续{//月进位_day -= GetMonthDay(_year, _month); //减去当前月的天数++_month; //来到下一月//月进位后判断年是否需要进位if (_month == 13){++_year;_month = 1; //进位后月份来到了1月}}return *this;}

不过需要注意的是:上面的代码我们对日期进行了修改,返回的是修改后的对象,故实现的不是"+"号的运算符重载,而是"+="运算符的重载。

        那如果我们要实现"+"号呢?很简单,拷贝一份原对象,然后对拷贝后的对象复用"+="运算符重载即可,这样就不会对原对象进行修改。代码如下:

// 日期+天数Date operator+(int day){Date tmp(*this); //拷贝构造一个临时变量tmp += day; //复用+=运算符,此时tmp就是加上day后的日期,但原对象并没有改变return tmp; //以值的形式返回}

        日期 - 指定天数

        实现了推算几天后的日期,我们再来实现推算几天前的日期。同样的,我们先实现"-="运算符的重载,然后"-"号运算符进行复用即可。

        日期+天数是进行进位,那么日期-天数就是进行借位退位,二者互为逆过程。有一点需要注意的是,退位借的是上一个月的天数,故我们需要先让月先减再让天数增加。动图如下:

        下面是是示例代码(初版): 

// 日期-=天数(初版)Date& operator-=(int day){_day -= day; //先全部减到_day上while (_day <= 0) //_day小于0说明需要借位,进行循环{//月先借位--_month;//月借位后判断年是否需要借位if (_month == 0){--_year; //年借位_month = 12; //月变为上一年12月}_day += GetMonthDay(_year, _month); //将借到的天数进行累加}return *this;}

         实现了日期-=天数,那么日期-天数直接复用即可

// 日期-天数Date operator-(int day){Date tmp(*this); //拷贝构造tmp -= day; //复用-=运算符return tmp;}

        细心的小伙伴可能发现了,上面我们写的"+=""-="运算符重载都是初版,是有哪里要改进吗?没错,其实上面的代码在特殊情况下有出错的风险,即用户传入的天数如果是个负数,那么最终得到的答案可能就不是我们想要的。但是我们再来看看网上的日期计算器

        没错,网上的日期计算器对负数有着特殊处理,输入负数时则是向前计算,即减去相应的天数。故我们可以参考进行实现:

// 日期+=天数(终版)Date& operator+=(int day){if (day < 0) //先判断day的正负{*this -= (-day); //为负数则复用-=运算符return *this; //直接返回} _day += day; //先将天数全部加到_day上        //下面开始进行进位while (_day > GetMonthDay(_year, _month)) //当_day大于本月的天数说明还需要进行进位,继续{//月进位_day -= GetMonthDay(_year, _month); //减去当前月的天数++_month; //来到下一月//月进位后判断年是否需要进位if (_month == 13){++_year;_month = 1; //进位后月份来到了1月}}return *this;}

对于"+="运算,我们通过复用"-="实现对负数的特殊处理。而对于"-="运算,我们可以复用"+="实现对负数的特殊处理,这里就不再展开了。

3.6 自增与自减运算符重载

        在上面实现日期+=天数和日期-=天数的基础上,我们通过复用可以很轻松地实现自增和自减运算符重载,代码如下:

// 前置++Date& operator++(){    *this += 1; //先+1return *this; //再返回,返回+1后的结果}// 后置++Date operator++(int) //int用于占位,表示后置++{Date tmp(*this); //拷贝一份*this += 1; //然后+1return tmp; //返回+1前的结果}// 前置--Date& operator--(){    *this -= 1; //先-1return *this; //再返回,返回-1后的结果}// 后置--Date operator--(int) //int用于占位,表示后置--{Date tmp(*this); //拷贝一份*this -= 1; //然后-1return tmp; //返回-1前的结果}

3.7 日期 - 日期

        我们知道,日期+日期是没有意义的,但日期-日期却是很有价值的,可以用来获取两个日期之间间隔的天数。故我们最后还要来实现"-"号运算符的另外一个重载版本,用于进行日期-日期的运算。

        由于日期类的运算规则较为复杂,涉及到每年的天数不同每月的天数不同,以及平闰年之分,如果采用正常的年-年,月-月的方法,想想都头大

        故我们另辟稀径,我们可以先找出较小的那个日期,然后让较小的日期不断+1,用一个变量count来统计+1的次数,直到较小的日期和较大的日期相等时,count的值不就是我们要求的差值嘛代码如下:

// 日期-日期 返回天数//法1:年-年,月-月,日-日,太过复杂//法2:找出较小的那个,一直累加直到等于大的那个,累加的次数就是之间的天数int operator-(const Date& d){    //找出较小的那个日期,这里先假设*this较小Date min = *this;Date max = d;int flag = -1; //用于表示最后相减结果的符号if (min > max) //假设不成立,互换{min = d;max = *this;flag = 1;}    //小的进行累加,直到二者相等int ret = 0; //统计min累加的次数while (max > min){min++;        ret++; }return ret*flag; //最终累加的次数即为日期差}

四. 完整代码 

        最后给出本期日期类的完整代码,需要的读者自取

class Date{public:// 获取某年某月的天数int GetMonthDay(int year, int month){//用一个数组表示平年每月的天数,下标表示月份int MouthDayArray[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)) //判断闰年{MouthDayArray[2]++; //是闰年,2月份天数+1}return MouthDayArray[month]; //返回当前月天数}// 全缺省的构造函数Date(int year = 2023, int month = 1, int day = 1){if (month < 1 || month > 12 || day < 1 || day > GetMonthDay(year, month)){cout << "日期非法" << endl;exit(-1);}_year = year;_month = month;_day = day;}// 拷贝构造函数, d2(d1)Date(const Date& d) //加const避免d被意外修改,使用引用传递是为了提高效率{_year = d._year;_month = d._month;_day = d._day;}//赋值运算符重载,不需要显式进行实现,使用编译器默认生成的即可Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this; //返回当前对象的引用为了实现链式访问}// 析构函数~Date() {};// 日期+=天数Date& operator+=(int day){if (day < 0){*this -= (-day);return *this;}_day += day;while (_day > GetMonthDay(_year, _month)){//月进位_day -= GetMonthDay(_year, _month);++_month;//年进位if (_month == 13){++_year;_month = 1;}}return *this;}// 日期+天数Date operator+(int day){if (day < 0){return *this - (-day) ;}Date tmp(*this); //拷贝构造tmp += day; //复用+=运算符return tmp;}// 日期-=天数Date& operator-=(int day){if (day < 0){*this += (-day);return *this;}_day -= day;while (_day <= 0){//月让位--_month;//年让位if (_month == 0){--_year;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;}// 前置++Date& operator++(){*this += 1; //先+1return *this; //再返回,返回+1后的结果}// 后置++Date operator++(int) //int用于占位,表示后置++{Date tmp(*this); //拷贝一份*this += 1; //然后+1return tmp; //返回+1前的结果}// 前置--Date& operator--(){*this -= 1; //先-1return *this; //再返回,返回-1后的结果}// 后置--Date operator--(int) //int用于占位,表示后置--{Date tmp(*this); //拷贝一份*this -= 1; //然后-1return tmp; //返回-1前的结果}// >运算符重载bool operator>(const Date& d){if (_year > d._year) //比较年{return true;}else if (_year == d._year && _month > d._month) //年相等比较月{return true;}else if (_year == d._year && _month == d._month && _day > d._day) //年月都相等比较日{return true;}else //前面的条件都不符合,说明日期比较小,返回false{return false;}}// ==运算符重载bool operator==(const Date& d){return (_year == d._year) && (_month == d._month) && (_day == d._day);}// <运算符重载bool operator<(const Date& d){//*this表示当前对象return !((*this == d) || (*this > d)); //逻辑非之后表示既不大于也不等于}// >=运算符重载bool operator >= (const Date& d){return !(*this < d); //复用<运算符}// <=运算符重载bool operator <= (const Date & d){return !(*this > d); //复用>运算符}// !=运算符重载bool operator != (const Date& d){return !(*this == d); //复用==运算符}// 日期-日期 返回天数//法1:年-年,月-月,日-日,太过复杂//法2:找出较小的那个,一直累加直到等于大的那个,累加的次数就是之间的天数int operator-(const Date& d){//找出较小的那个日期,这里先假设*this较小Date min = *this;Date max = d;int flag = -1; //用于表示最后相减结果的符号if (min > max) //假设不成立,互换{min = d;max = *this;flag = 1;}//小的进行累加,直到二者相等int ret = 0; //统计min累加的次数while (max > min){min++;ret++;}return ret * flag; //最终累加的次数即为日期差}//打印数据void Print(){cout << _year << "年" << _month << "月" << _day << "日" << endl;}private:int _year;int _month;int _day;};

以上,就是本期的全部内容啦🌸

制作不易,能否点个赞再走呢🙏

来源地址:https://blog.csdn.net/m0_69909682/article/details/132537165

--结束END--

本文标题: 【C++深入浅出】日期类的实现

本文链接: https://www.lsjlt.com/news/411897.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 【C++深入浅出】日期类的实现
    目录 一. 前言  二. 日期类的框架 三. 日期类的实现 3.1 构造函数 3.2 析构函数 3.3 赋值运算符重载 3.4 关系运算符重载 3.5 日期 +/- 天数 3.6 自增与自减运算符重载 3.7 日期 - 日期 四. 完整...
    99+
    2023-09-18
    c++ 类和对象 日期类 运算符重载
  • 【C++深入浅出】类和对象下篇
    一. 前言         老样子,先来回顾一下上期的内容:上期我们着重学了C++类中的六大默认成员函数,并自己动手实现了一个日期类,相信各位对C++中的类已经有了一定程度的了解。本期就是类和对象的最后一篇啦,终于要结束咯,吧唧吧唧  ...
    99+
    2023-10-10
    c++ 开发语言 初始化列表 static成员 友元 匿名对象 explicit关键字
  • C语言深入浅出讲解顺序表的实现
    目录1.线性表2.顺序表2.1 概念及结构2.2 提供接口2.3 接口实现今天起开始编写数据结构中的各种数据结构及算法的实现,说到顺序表,我们首先得了解下线性表。 1.线性表 线性表...
    99+
    2022-11-13
  • C++深入浅出讲解希尔排序算法的实现
    目录希尔排序1.基本思想预排序2.算法实现3.时间复杂度插入排序分为两种:直接插入排序&希尔排序 希尔排序 1.基本思想 希尔排序是在直接插入排序基础上的优化,属于非常牛掰的...
    99+
    2022-11-13
  • 深入浅析Java8中日期与时间的特性
    深入浅析Java8中日期与时间的特性?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。日期是商业逻辑计算一个关键的部分,任何企业应用程序都需要处理时间问题。应用程序...
    99+
    2023-05-31
    java8 ava 中日
  • C++类与对象之日期类的实现
    目录1. 实现前的铺垫2. 日期类的实现2.1 日期+=天数2.2 日期-=天数2.3 日期-天数2.4 日期+天数2.5 前置++2.6 后置++2.7 前置–2.8 后置–2.9...
    99+
    2022-11-12
  • 深入浅出Golang中select的实现原理
    目录概述select实现原理执行流程case数据结构执行select循环总结概述 在go语言中,select语句就是用来监听和channel有关的IO操作,当IO操作发生时,触发相应...
    99+
    2022-11-11
  • 深入浅出讲解Java中的枚举类
    目录一、枚举类的使用 二、如何定义枚举类 背景:类的对象只有有限个,确定的。举例如下: > 星期: Monday (星期一)、….、 Sunday (星期天) > 性别:...
    99+
    2022-11-12
  • C语言深入浅出讲解直接插入排序算法的实现
    目录直接插入排序1.基本思想2.算法实现3.时间复杂度插入排序分为两种:直接插入排序&希尔排序 直接插入排序 1.基本思想 直接插入排序是一种简单的插入排序算法,其基本思想是...
    99+
    2022-11-13
  • C++实现日期类的示例详解
    目录一、获取某年某月的天数二、Date的默认成员函数(全缺省的默认构造)三、运算符重载1.+ =、+、- =、-2.==、!=、>、>=、<、<=3.前置++...
    99+
    2023-02-07
    C++实现日期类 C++常见日期类 C++日期类
  • C++日期类(Date)实现的示例代码
    目录类的定义确定某年某月有多少天构造函数打印日期日期+=天数日期+天数日期-=天数日期-天数前置++后置++后置–前置–>运算符重载==运算符重载>...
    99+
    2022-11-13
  • C++深入浅出探索数据结构的原理
    目录一、前言二、C++的数据结构三、定义结构四、访问结构成员五、结构作为函数参数六、指向结构的指针一、前言 因为C++的数据结构很多,很复杂,一篇文章根本讲不到所有的数据结构。即使写...
    99+
    2022-11-13
  • C语言深入浅出讲解指针的使用
    目录一、利用指针倒序字符串二、题目实例三、总结一、利用指针倒序字符串 void _reversal(char* left, char* right) { while (lef...
    99+
    2022-11-13
  • redis深入浅出分布式锁实现上篇
    目录问题描述解决方案编写代码优化之UUID防误删问题描述 随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原...
    99+
    2022-11-13
  • redis深入浅出分布式锁实现下篇
    目录优化之UUID防误删项目中正确使用总结优化之UUID防误删 问题:删除操作缺乏原子性。 场景: index1执行删除时,查询到的lock值确实和uuid相等 uuid=v1 ...
    99+
    2022-11-13
  • C++深入浅出讲解隐藏this指针的用法
    目录1.this指针的引出2.this指针的特性3.练习一下本篇文章我们将一起讨论在有趣的知识点--隐藏的this指针。本篇我们要使用到之前我们所学习到的C++类与对象,如果有各位小...
    99+
    2022-11-13
  • C++无痛实现日期类的示例代码
    目录日期类的实现构造函数析构函数拷贝构造函数打印函数获取天数函数运算符重载区赋值重载整体代码Date.hDate.cpp日期类的实现 凡是要写类必须要提到六大默认成员(六位大爷):构...
    99+
    2022-11-13
    C++实现日期类 C++日期类
  • C++深浅拷贝及简易string类实现方式
    目录三种拷贝方式浅拷贝深拷贝写时拷贝VS与GCC中的拷贝方式Windows VS2022Linux GCC简易string类传统版写法的string类现代版写法string类总结三种...
    99+
    2023-02-05
    C++深浅拷贝 C++实现string类 C++ string类
  • C++深浅拷贝及简易string类怎么实现
    这篇“C++深浅拷贝及简易string类怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++深浅拷贝及简易strin...
    99+
    2023-07-05
  • 深入浅出理解C语言指针的综合应用
    目录指针是什么?指针变量  使用指针变量的例子通过指针引用数组&数组名vs数组名野指针野指针成因1.指针未初始化2.指针越界访问如何避免野指针指针运算指针是什么? ...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作