前言
前面我们讲解了类的对象的大部分知识,例如拷贝构造,函数重载等知识,本节我们将用所学的知识对日期类进行实现。
注意:本篇博客代码的实现综合了前面所学,同时可能会捎带一点点后面所学内容。
1.头文件的实现
定义日期的类,对公共部分的函数进行声明,私有成员的确定。
函数有日期输入输出,日期判断,日期的大小比较,日期增减。
#pragma once #include <iostream> #include <assert.h> using namespace std; class Date { friend ostream& operator<<(ostream& out, const Date&d); friend istream& operator>>(istream& in, Date& d); public: Date(int year = 1, int month = 1, int day = 1); void Print(); int Getday(int year, int month) const{ assert(month > 0 && month < 13); static int monthDayArray[13] = { -1, 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; } else return monthDayArray[month]; } bool CheckDate(); 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; // d1 += 天数 Date& operator+=(int day); Date operator+(int day) const; // d1 -= 天数 Date& operator-=(int day); Date operator-(int day) const; // d1 - d2 int operator-(const Date& d) const; // ++d1 -> d1.operator++() Date& operator++(); // d1++ -> d1.operator++(0) // 为了区分,构成重载,给后置++,强⾏增加了⼀个int形参 // 这⾥不需要写形参名,因为接收值是多少不重要,也不需要⽤ // 这个参数仅仅是为了跟前置++构成重载区分 Date operator++(int); Date& operator--(); Date operator--(int); // 流插⼊,流输入输出 // 不建议,因为Date* this占据了⼀个参数位置,使⽤d<<cout不符合习惯 //void operator<<(ostream& out); private: int _year; int _month; int _day; }; ostream& operator<<(ostream& out, const Date&d); istream& operator>>(istream& in, Date& d);
在这里,我们用了一个数组来存取各月份的天数,避免连续用多个if else选择语句使代码冗杂,痛过闰年判断来进一步决定二月份的天数。
这个获取月份天数我们要频繁调用,所以我们直接定义在类里面,默认内联函数,频繁调用。
2.日期类函数各项功能实现
因为是在.cpp文件,在我们定义的头文件Date类以外,所以类外声明我们要用到 :: 操作符。
即Date::
2.1 初始化和打印(比较简单)
bool Date::CheckDate() { if (_month < 1 || _month > 12 || _day < 1 || _day > Getday(_year, _month)) { return false; } else { return true; } } Date::Date(int year, int month, int day) { _year = year; _month = month; _day = day; if (!CheckDate()) { cout << "⽇期⾮法" << endl; } } void Date::Print(){ cout << _year << "-" << _month << "-" << _day << endl; }
这里我们写了个检查日期函数,为了方便判断我们所给定的日期是否是非法的,也使日期类函数功能更加完善。
2.2日期大小判断
判断日期大小,从年月日依次判断,通过代码发现,只要实现了基本的等于和大小判断,其他的判断实现我们都可以用过逻辑运算形式来实现。这样可以减少代码量。
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; else return false; } else return false; } bool Date::operator<=(const Date& d) const { return *this < d || *this == d; } /* 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; else return false; } else return false; } */ bool Date::operator>(const Date& d) const { return !(*this < d); } bool Date::operator>=(const Date& d) const { return *this > d || *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); }
2.3日期的加减运算
对于加减运算看起来简单,思路也挺丰富,但是通过代码实现还是有一定的难度的,接下来小编带领大家分析实现。
日期加天数
对于日期加天数,我们要进位并且还要判断是否满年和满该月,然后向前加。
Date& Date::operator+=(int day) { if (day < 0) { return *this -= (-day); } _day += day; // 将传入的天数加到当前日期的天数上 while (_day > (Getday(_year, _month))) { // 检查当前日期是否超过了这个月的天数 _day -= Getday(_year, _month); // 减去这个月的天数 _month++; // 月份加一 if (_month == 13) { // 如果月份超过 12 _month = 1; // 重置为 1 _year++; // 年份加一 } } return *this; // 返回当前对象的引用 }
这里的返回是传引用返回,在原来的日期上进行修改,更好的支持链式操作,当然我们也可以通过传值返回,只不过要拷贝一份,加临时变量。
为了方便区分理解,传引用我们定义为+=,传值为+
传值调用法可以借鉴+=的思路,创建一个临时变量temp,在所有成员前面加temp.即可
Date Date::operator+(int day) const{ Date temp = *this; temp._day += day; while (temp._day > (Getday(temp._year, temp._month))) { temp._day -= Getday(temp._year,temp. _month); temp._month++; if (temp._month == 13) { temp._month = 1; temp._year++; } } return temp; }
当然一个简便的方法是临时生成一个temp,通过+=函数改变temp,再返回temp。
Date Date::operator+(int day)const { Date temp = *this; temp += day; return temp; }
日期减天数
我们要采取借位的方法,通过用上一个月份的天数加到_day上,直到>0为止。
Date& Date::operator-=(int day) { if (day < 0) { return *this += (-day); } _day -= day; // 从当前日期的天数中减去传入的天数 while (_day <= 0) { // 检查当前日期的天数是否小于或等于0 _month--; // 减少月份 if (_month == 0) { // 如果月份变为0,意味着需要回到上一年 _month = 12; // 将月份重置为12 _year--; // 年份减少 } _day += Getday(_year, _month); // 为当前月份添加天数 } return *this; // 返回当前对象的引用, }
手把手教你实现日期类(下):https://developer.aliyun.com/article/1624944