前言
这是我们需要实现的日期类的接口声明,我们需要的是在Date.cpp文件中实现函数的定义.
class Date { public: // 获取某年某月的天数 int GetMonthDay(int year, int month); //打印日期类函数 void Print(); // 全缺省的构造函数 Date(int year = 1900, 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); // 前置++ 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); // 日期-日期 返回天数 int operator-(const Date& d); private: int _year; int _month; int _day; };
一、构造函数
1.1 默认构造函数
声明:(在Date类中)
//Date.h // 全缺省的构造函数 Date(int year = 2023, int month = 1, int day = 1);
定义:
//Date.cpp Date::Date(int year , int month, int day) { _year = year; _month = month; _day = day; //这里也就体现出了,成员变量前面'_'的好处,方便与参数区分 }
这里需要注意的是,缺省参数应该在声明处给出,定义时不能有缺省参数,在C++入门章节牛牛有提到过原理.
1.2 拷贝构造函数
使用场景:
Date d1(2023, 4, 26); Date d2(d1);//使用已存在的对象去初始化另一个对象,被称为拷贝构造
定义:
//Date.cpp // 拷贝构造函数 Date::Date(const Date& d) { _year = d._year; _month = d._month; _day = d._day; }
注意使用引用传参.
二、获取天数
放在以前,牛牛实现获取天数的函数可能会用一个很长的Switch case语句,然后返回每一个天数的时间.
如今,牛牛发现,除了闰年时2月是29天以外,其他时候,每个月的时间是不变的,我们可以使用数组将每个月的天数存起来.
int Date::GetMonthDay(int year, int month) { int day[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))//如果是闰年,且是2月 { day[2] = 29; } return day[month]; }
这里需要注意的是判断条件month == 2要放在前面
((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)放在后面,因为前面的判断条件很好判断,后面的比较复杂,这样可以提高效率.
三、运算符重载
3.1 赋值运算符重载
注意:
参数const Date& d
1.const一方面保证右操作数不会被修改,即防止函数写反了功能.
例如:参照错误写法.
d1=d2,结果是将d2修改成了d1,偷鸡不成蚀把米.
2.Date&传引用就不会调用拷贝构造函数去传参,减少拷贝,提高效率.
//运算符重载 Date& Date::operator=(const Date& d) { _year = d._year; _month = d._month; _day = d._day; return *this; } //错误写法 Date& Date::operator=(Date& d) { d._year=_year; d._month=_month; d._day=_day; return *this; }
3.2 日期+=天数
示例: 2023年7月28日+80天
需要注意的是,如果month往后推一位后为13,则应当将month设置为1,并且year++.
代码实现:
// 日期+=天数 Date& Date:: operator+=(int day) { if (day < 0)//不知道使用者会不会调皮传过来负数 { return *this -= -day;//调用"-="的运算符重载 } _day += day; while (_day > GetMonthDay(_year, _month))//如果超过当月天数 { _day -= GetMonthDay(_year, _month);//通过调用GetMonthDay函数获取当月天数 _month++; if (_month > 12)//月数超过12,则开始下一年 { _month = 1; _year++; } } return *this; }
3.3 日期+天数
与日期+=天数不同,日期+天数要求该日期本身没有改变,而是返回日期+天数后的日期
此时,我们需要创建一个临时Date 类ret,将增加的天数与ret进行计算,最后返回ret对象.
// 日期+天数 Date Date:: operator+(int day) { if (day < 0) { return *this -= -day;//调用"-="的运算符重载 } Date ret;//创建临时对象 ret._day += day; while (ret._day > GetMonthDay(_year, _month))//如果超过当月天数 { ret._day -= GetMonthDay(_year, _month); ret._month++; if (ret._month > 12) { ret._month = 1; ret._year++; } } return ret; }
3.4 日期-=天数 和 日期-天数
示例:2023年7月28日-100天
需要注意的是,重点是+上月的天数,而不是本月的天数.
// 日期-=天数 Date& Date:: operator-=(int day) { if (day < 0) { return *this += -day;//调用"+="的运算符重载 } _day -= day; while (_day <= 0)//如果是负数 { _month--; if (_month <= 0) { _month = 12; _year--; } _day += GetMonthDay(_year, _month); } return *this; }
到了这里,我想日期-天数的实现应该比较简单,牛牛就不多介绍了.
// 日期-天数 Date Date::operator-(int day) { if (day < 0) { *this -= day;//调用"-="的运算符重载 } Date ret; ret._day -= day; while (ret._day <= 0)//如果是负数 { ret._day += GetMonthDay(_year, _month-1);//+上个月的总天数 ret._month--; if (ret._month <=0) { ret._month = 12; ret._year--; } } return ret; }
3.5 日期-日期
日期-日期怎么计算?
例如:
2023年7月28号距离2024年1月1号还有几天?
如果对应的年月日进行想减,然后还需要计算是那些年有那些天,月数又有几天,那可就太麻烦了吧.
所以我们直接先判断两个日期的大小,选择用较小的日期,对齐进行++操作,直到与较大的相等,统计++了多少天,这样是不是就很简单了?
步骤:
1.比较日期大小,选出较小者.
2.对较小者进行++并统计,直到与较大者相等.
3.返回统计的天数.
// 日期-日期 返回天数 int Date::operator-(const Date& d) { //小的日期一直++,加到和大的日期一样时,加了多少次就差多少天 Date max = *this; Date min = d; int flag = 1; if (*this < d)//如果是左操作数小,则应当是负数 { max = d; min = *this; flag = -1; } int n = 0; while (min != max)//用n统计相差多少天 { ++min; ++n; } return n * flag; }
3.6 前置++与后置++
前置++与后置++实现的时候有一个很尴尬的问题,因为前置++和后置++都是单目运算符,即只有一个操作数,那么为了实现他们两个函数能够重载,则只能在后置++处添加一个int类型的参数.
这个参数用户在使用时不需要传递,编译器会自动传递,本质是为了让前置++和后置++进行函数重载.
前置++是返回+1之后的结果,并且this是指向对象本身的,所以我们可以使用传引用返回,减少拷贝,提高效率.
后置++是返回+1之前的值,并且对象最终还需要被修改,所以我们需要创建一个临时对象用于记录+1前对象的日期大小.除此之外,因为临时变量是在局部定义的,所以我们必须传值返回,不能传引用返回.
// 前置++ Date& Date:: operator++() { _day +=1; while (_day > GetMonthDay(_year, _month))//如果超过当月天数 { _day -= GetMonthDay(_year, _month);//则减去当月的天数 //月份向后推一个月 _month++; if (_month > 12) { _month = 1; _year++; } } return *this; } // 后置++ Date Date::operator++(int)//这个参数为了个与前置++构成函数重载,调用的时候不需要传参. { Date tmp = *this;//要保存++前日期的大小. _day += 1; while (_day > GetMonthDay(_year, _month))//如果超过当月天数 { _day -= GetMonthDay(_year, _month); _month++; if (_month > 12) { _month = 1; _year++; } } return tmp; }
3.7 前置–与后置–
学了前置++与后置++,这里也是类似的,需要注意的是,+上月的天数.
// 前置-- Date& Date::operator--() { _day -= 1; while (_day <= 0)//如果是负数 { _day += GetMonthDay(_year, _month - 1);//+上个月的总天数 _month--; if (_month <= 0) { _month = 12; _year--; } } return *this; } // 后置-- Date Date::operator--(int) { Date tmp = *this; _day -= 1; while (_day <= 0)//如果是负数 { _day += GetMonthDay(_year, _month - 1);//+上个月的总天数 _month--; if (_month <= 0) { _month = 12; _year--; } } return tmp; }
3.8 比较运算符
比较运算符重载我不多介绍了,没有什么难度.
需要学习的是,可以使用已经实现的>和"=="去复用实现剩下的其他运算符
bool Date::operator>(const Date& d) { if (_year > d._year)//如果年大 { return true; } { if (_year == d._year) { if (_month > d._month)//年相同,月大 { return true; } else { if (_day > d._day)//入如果年月相同,日大 { return true; } return false;//月小,或者日小和相等 } } return false;//如果年小 } }
// ==运算符重载 bool Date::operator==(const Date& d) { if (_year == d._year&& _month== d._month&& _day==d._day ) { return true; } return false; } // >=运算符重载 bool Date::operator >= (const Date& d) { if (*this > d|| *this == d) { return true; } return false; } // <运算符重载 bool Date::operator < (const Date& d) { return !(*this >= d); } // <=运算符重载 bool Date::operator <= (const Date& d) { return !(*this > d); } // !=运算符重载 bool Date::operator != (const Date& d) { return !(*this == d); }
日期类就简单实现到这里了,友友们下次见,总代码,可以去我的资源处下载源代码哦.