学习目标:
加深对四个默认构造函数的理解:
1.构造函数
2.析构函数
3.拷贝构造
4.运算符重载
实现功能
1.比较日期的大小
2.日期+-天数
3.前/后置++,--
这里基本会使用运算符重载
定义一个日期类
class Date { public: //1.全缺省参数的构造函数 Date(int year = 1, int month = 1, int day = 1) { _year = year; _day = day; _month = month; } //2.构造拷贝函数 Date(const Date& x) { _year = x._year; _month = x._month; _day = x._day; } //3.析构函数(这里可不构造) ~Date() {} //4.运算符重载 bool operator==(const Date& x); private: int _year; int _month; int _day; };
1.比较日期的大小
比较日期大小,只用写大于,等于或者小于,等于,其它功能去复用就行(关系互斥)
--功能声明:
--等于实现:
//等于(d1 == d2;) bool Date::operator==(const Date& x) { return this->_year == x._year && this->_month == x._month && this->_day == x._day; }
--大于实现:
//大于(d1>d2) bool Date::operator>(const Date& x) { if ((_year > x._year) || ((_year == x._year) && (_month > x._month)) || ((_year == x._year) && (_month == x._month) && (_day > x._day))) return true; else return false; }
--小于等于
//小于等于(d1<=d2) bool Date::operator<=(const Date& x) { return !(*this > x); }
--大于等于
//大于等于 bool Date::operator>=(const Date& x) { return (*this > x) || (*this == x); }
--小于:
//小于(d1<d2) bool Date::operator<(const Date& x) { return !(*this >= x); }
--不等于:
//不等于 bool Date::operator!=(const Date& x) { return !(*this == x); }
效果:
2.日期+-天数
准备工作:日期+-天数,要考虑到进位,借位,以及闰年,非闰年的月份天数问题:
给出函数:
--是否为闰年:
//是否为闰年 int is_leapyear(int year) { if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) { return 1; } return 0; }
--获取月分的天数:
//获取每一个月份的天数 int GetMonthDay(int year, int month) { int month_day[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//存放每个月的月份 int is_leap = is_leapyear(year); if (is_leap && month == 2) { return month_day[month] + 1;//是闰年,2月有29天 } else { return month_day[month];//不是闰年且不是2月 } }
功能声明:
这里同样可以实现复用:
写好+=后可以复用+,写好-=可以复用-
为什么不是+复用+=呢?
--+天数不改变原来日期,+=会改变,直接用+=复用的时候,拷贝一份,传+=后的即可
实现:
日期+=天数
//日期+=天数(d1 += 100) Date Date::operator+=(int day) { if (day < 0) { return *this -= -day; } //1.直接将天数加到该日期的月数中去 _day += day; //2.判断是否超出当前月数的天数 while (_day > GetMonthDay(_year,_month)) { //3.超出就进位,重复 _day -= GetMonthDay(_year,_month); _month++; //处理年份 if (_month == 13) { _month = 1; _year++; } } return *this; }
日期+天数
//日期+天数(d1+100) Date Date::operator+(int day) { //+,不改变date,拷贝一份 Date ret(*this); ret += day; return ret; }
日期-=天数:
//日期 -= 天数( d1 - 100) Date Date::operator-=(int day) { if (day < 0) { return *this += -day; } //1.天减去天 _day -= day; //2.判断是否违法,违法向前面借 while (_day <= 0) { _month--; //借月数 if(_month <= 0) { _year--; _month = 12; } //借天数 _day += GetMonthDay(_year, _month); } return *this; }
日期-天数:
//日期 - 天数( d1 - 100) Date Date::operator-(int day) { //不改d1,拷贝一下 Date tmp(*this); tmp -= day; return tmp; }
日期-日期:
//日期-日期 - int Date::operator-(const Date& d) { Date max = *this; Date min = d; int flag = 1; //1.找出较小的日期 if (*this < min) { max = d; min = *this; flag = -1; } int n = 0; //2.让较小的日期一直+,直到等于较大的日期(加了多少次,它们就差了多少天) while (min != max) { ++min; ++n; } //flag用来处理大年减小年或小年减大年的情况 return n*flag; }
赋值运算符重载(=)
//赋值 void Date::operator=(const Date& x) { _year = x._year; _month = x._month; _day = x._day; }
效果:
3.前/后置++,--
前/后置++,--会有歧义:
如++运算符重载后的到底是前置++,还是后置++呢?
这里使用函数重载解决,改变形参来区分
这里说明一下为什么前置可以使用引用返回,后置却不行:
--前置会先改变d1,再++,直接把d1传回去就行了
--后置会先使用原来的,再++,所有要拷贝一份,传回去的是拷贝的tmp,出栈就销毁了,所有不能传引用
++:
//前置++ Date& Date::operator++() { *this += 1; return *this; } //后置++ Date Date::operator++(int) { Date tmp(*this); *this += 1; return tmp; }
--:
1
//前置-- Date& Date::operator--() { *this -= 1; return *this; } //后置-- Date Date::operator--(int) { Date tmp(*this); *this -= 1; return tmp; }
效果: