用于打印日期类
2.运算符重载接口实现
2.1日期比较
2.1.1 <运算符重载
bool Date:: operator < ( const Date& x)
{
if ( _year < x. _year)
{
return true ;
}
else if ( _year == x. _year && _month < x. _month)
{
return true ;
}
else if ( _year == x. _year && _month == x. _month && _year < x. _year)
{
return true ;
}
return false ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
实现日期小于的比较
,我们要先思考日期的比较需要分别比较年月日
,从年开始依次比较,一旦成立则说明小于成立;反之应该是大于,小于不成立
🔥值得注意的是:
传参时要特别注意,运算符有几个操作数,就传几个参数
,this指针也算在参数中
, 所以这里默认<左边的对象是用this指针
传过去了,右边的对象引用传参
(加const避免被传的数值被修改,引用传参提高效率) 这里的运算符重载函数是成员函数
调试状态下,转到反汇编比较可以观察到,两种写法的底层代码是一样的,说明了d1 < d2
会转换成d1.operator<(d2)
如果是非成员函数的情况下呢?
bool Date:: operator < ( const Date& x1, const Date& x2)
{
if ( x1. _year < x2. _year)
{
return true ;
}
else if ( x1. _year == x2. _year && x1. _month < x2. _month)
{
return true ;
}
else if ( x1. _year == x2. _year && x1. _month == x2. _month && x1. _year < x2. _year)
{
return true ;
}
return false ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
注意在类内要添加友元的声明
,在类外定义
运算符重载函数 时,要传两个参数
,原因在于非成员函数没有隐含的 this 指针来指向调用对象
。不像成员函数,通过 this 指针隐式获取左侧对象,只需要显式接收右侧对象作为参数
同样转到反汇编比较,可以观察到非成员函数
下,d1 < d2
会转换成operator<(d1, d2)
,底层代码也清晰的指出要传几个参数
2.1.2 ==运算符重载
bool Date:: operator == ( const Date& x)
{
return _year == x. _year
&& _month == x. _month
&& _day == x. _day;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
==的运算符重载
很简单,直接返回即可,如果相等返回true
;反之则为false
2.1.3 <=运算符重载
bool Date:: operator <= ( const Date& x)
{
return * this < x || * this == x;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
显而易见,注意左边的数是由this指针隐式传递
,满足小于或等于
都能成立
2.1.4 >运算符重载
bool Date:: operator > ( const Date& x)
{
if ( _year > x. _year)
{
return true ;
}
else if ( _year == x. _year && _month > x. _month)
{
return true ;
}
else if ( _year == x. _year && _month == x. _month && _year > x. _year)
{
return true ;
}
return false ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
大于的运算符重载
和小于的同理,修改符号即可
但是这样写实在是太麻烦了,根据上面写的==的运算符重载
,>=运算符重载
和<运算符重载
,可以极大的简化和日期类比较
有关的函数
bool Date:: operator > ( const Date& x)
{
return ! ( * this <= x) ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
<=
的反面就是>
,借助这一点能够减少很多不必要的代码
2.1.5 >=运算符重载
bool Date:: operator >= ( const Date& x)
{
return ! ( * this < x) ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
同理,借助刚写完的>运算符重载
也能简单的写出>=运算符重载函数
2.1.6 !=运算符重载
bool Date:: operator != ( const Date& x)
{
return ! ( * this == x) ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
==运算符重载
取反即可
2.2 日期与天数的计算
2.2.1 日期+=天数
首先我们要明白日期+天数
如何计算,那么经过举例演算可以发现,用进位的方式
实现日期+天数,简单来说就是天满了往月进,月满了往年进
,依赖于GetMonthDay函数处理每个月的天数
,不断减掉天数直到合法为止
Date& Date:: operator += ( int day)
{
if ( day < 0 )
{
* this -= - day;
}
_day += day;
while ( _day > GetMonthDay ( _year, _month) )
{
_day -= GetMonthDay ( _year, _month) ;
++ _month;
if ( _month == 13 )
{
++ _year;
_month = 1 ;
}
}
return * this ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
因为我们是在原本的日期
上操作,所以是+=
且引用返回
,而不是+
,注意加上负数等同于减去正数
,也可以用abs取绝对值
Date& Date:: operator += ( int day)
{
* this = * this + day;
return * this ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
+=
还可以利用下面实现的日期+天数
的运算来写
2.2.2 日期+天数
Date Date:: operator + ( int day)
{
Date tmp ( * this ) ;
tmp. _day += day;
while ( tmp. _day > GetMonthDay ( tmp. _year, tmp. _month) )
{
tmp. _day -= GetMonthDay ( tmp. _year, tmp. _month) ;
++ tmp. _month;
if ( tmp. _month == 13 )
{
++ _year;
tmp. _month = 1 ;
}
}
return tmp;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
那么真正的日期+天数
,应该是不会修改原来的日期的
,而是以另一个变量返回
,所以这里就可以利用拷贝构造
,将一个新的日期返回,注意不能引用返回
,因为tmp是局部变量
,出了作用域就被销毁了
Date Date:: operator + ( int day)
{
Date tmp ( * this ) ;
tmp += day;
return tmp;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
同理+
也可以利用日期+=天数
来运算,但是这两种简洁的写法不可能同时存在,因为至少要有一种是完整实现了的
,那么就可以对两种组合进行比对
考虑到变量的拷贝以及创建,明显是创建完整的+=运算,然后据此写+运算
更优,因为这个组合创建的对象更少
,减少对拷贝构造的调用
2.2.3 日期−=天数
举一反三,既然日期+天数是进位
,那么日期-天数就是借位
,每当被减成负数
的时候,要注意是向上个月借天数
,不是本月的天数
Date& Date:: operator -= ( int day)
{
if ( day < 0 )
{
* this += - day;
}
_day -= day;
while ( _day <= 0 )
{
-- _month;
if ( _month == 0 )
{
_month = 12 ;
-- _year;
}
_day += GetMonthDay ( _year, _month) ;
}
return * this ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
和+=
的写法其实大差不差,注意减去负数就是加上正数
2.2.4 日期−天数
Date Date:: operator - ( int day)
{
Date tmp ( * this ) ;
* this -= day;
return tmp;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
利用-=运算减少不必要的算法
,记得保存原先的日期
2.3 日期的自增自减
2.3.1 前置++
Date& Date:: operator ++ ( )
{
* this += 1 ;
return * this ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
在+=运算
的前提下,日期也是能实现自增的,所以不用担心自增后会不会越过当月的天数
,在+=已经处理好了
2.3.2 后置++
Date Date:: operator ++ ( int )
{
Date tmp = * this ;
* this += 1 ;
return tmp;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
后置++需要提前保存值
,因为是先使用再++
🔥值得注意的是:
前置++
和后置++
虽然是运算符重载
,但是形式上也构成函数重载
后置++
增加这个int参数不是为了接受具体的值
,仅仅是占位
,跟前置++
构成重载int这个位置传任何值都可以
,实际调用的时候前置++
和后置++
可能分别为d1.operator++()
和d1.operator++(0)
,括号内的值是随机的
2.3.3 前置−−
Date& Date:: operator -- ( )
{
* this -= 1 ;
return * this ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
−−的操作和++几乎是一样的
,这里就不过多赘述了
2.3.4 后置−−
Date Date:: operator -- ( int )
{
Date tmp = * this ;
* this -= 1 ;
return tmp;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
2.4 日期-日期
通常日期的计算我们一般是用来计算两个日期之前相差多少天
,因此我们的运算符重载是否有意义决定了是否要创建这个重载
,所以只考虑日期-日期
,日期+日期是没有意义的
根据前面的算法,我们也能很容易总结出计算方法,把年份大的的日期的月份天数
,假设成和一样的年份小的一样
,然后两者作天数差的计算
即可
其实还有更简单的思路,就是让年份小的日期一天一天去++
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)
{
++ min;
++ n;
}
return n * flag;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
这里最妙的是这个flag,能够刚好体现出计算的正负
,虽然这种方式没有上面那种来的快,但是这种程度的差距对于计算机来说其实是可以忽略不计的
2.5 日期的输入输出
基本数据类型基于cout和cin的使用
能够很方便的进行输入输出的操作,那么日期依托于运算符重载
也能达到此类效果,cout
和cin
分别属于iostram库
里的ostream
和istream
2.5.1 <<运算符重载
根据前面的经验,我们依旧把<<运算符重载放在成员函数里
void Date:: operator << ( ostream& out)
{
out << d. _year << "年" << d. _month << "月" << d. _day;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
可是当我们输出的时候就报错了,这是因为正常情况下cout<会转化成d1.operator<,Date对象默认占用第一个参数,也就是做了左操作数
,所以正确的写法应该是d1<才能正常输出,但是这样太奇怪了,完全不符合我们的使用习惯
ostream& operator << ( ostream& out, const Date& d)
{
out << d. _year << "年" << d. _month << "月" << d. _day;
return out;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
既然不能写成成员函数,那就在类外写成非成员函数
,就可以带入两个参数,cout<就会转化成operator<<(cout,d1)
,符合书写情况
🔥值得注意的是:
cout从左往右
连续输出,所以要返回ostream类型才能连续输出
类外访问私有变量使用友元函数
就能解决 ostream& out
前不能加const
,因为流插入就是不断改变cout
的过程
2.5.2 >>运算符重载
istream& operator >> ( istream& in, const Date& d)
{
in >> d. _year >> d. _month >> d. _day;
return in;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
同理,流输入也是同样的格式
3.代码展示
3.1 Date.h
# include
# include
using namespace std;
class Date
{
public :
friend ostream& operator << ( ostream& out, const Date& d) ;
friend istream& operator >> ( istream& out, const Date& d) ;
int GetMonthDay ( int year, int month)
{
static int days[ 13 ] = { 0 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 } ;
int day = days[ month] ;
if ( month == 2 && ( ( year % 4 == 0 && year % 100 != 0 ) || ( year % 400 == 0 ) ) )
{
day += 1 ;
}
return day;
}
Date ( int year = 1900 , int month = 1 , int day = 1 )
: _year ( year)
, _month ( month)
, _day ( day)
{ }
Date ( const Date& d)
{
_year = d. _year;
_month = d. _month;
_day = d. _day;
}
void Print ( )
{
cout << _year << '-' << _month << '-' << _day << endl;
}
bool operator < ( const Date& x) ;
bool operator > ( const Date& x) ;
bool operator >= ( const Date& x) ;
bool operator <= ( const Date& x) ;
bool operator == ( const Date& x) ;
bool operator != ( const Date& x) ;
Date& operator += ( int day) ;
Date operator + ( int day) ;
Date& operator -= ( int day) ;
Date operator - ( int day) ;
Date& operator ++ ( ) ;
Date operator ++ ( int ) ;
Date& operator -- ( ) ;
Date operator -- ( int ) ;
int operator - ( const Date& d) ;
private :
int _year;
int _month;
int _day;
} ;
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
3.2 Date.c
bool Date:: operator < ( const Date& x)
{
if ( _year < x. _year)
{
return true ;
}
else if ( _year == x. _year && _month < x. _month)
{
return true ;
}
else if ( _year == x. _year && _month == x. _month && _year < x. _year)
{
return true ;
}
return false ;
}
bool Date:: operator > ( const Date& x)
{
if ( _year > x. _year)
{
return true ;
}
else if ( _year == x. _year && _month > x. _month)
{
return true ;
}
else if ( _year == x. _year && _month == x. _month && _year > x. _year)
{
return true ;
}
return false ;
}
bool Date:: operator > ( const Date& x)
{
return ! ( * this <= x) ;
}
bool Date:: operator == ( const Date& x)
{
return _year == x. _year
&& _month == x. _month
&& _day == x. _day;
}
bool Date:: operator <= ( const Date& x)
{
return * this < x || * this == x;
}
bool Date:: operator >= ( const Date& x)
{
return ! ( * this < x) ;
}
bool Date:: operator != ( const Date& x)
{
return ! ( * this == x) ;
}
Date& Date:: operator += ( int day)
{
if ( day < 0 )
{
* this -= - day;
}
_day += day;
while ( _day > GetMonthDay ( _year, _month) )
{
_day -= GetMonthDay ( _year, _month) ;
++ _month;
if ( _month == 13 )
{
++ _year;
_month = 1 ;
}
}
return * this ;
}
Date Date:: operator + ( int day)
{
Date tmp ( * this ) ;
tmp += day;
return tmp;
}
Date& Date:: operator ++ ( )
{
* this += 1 ;
return * this ;
}
Date Date:: operator ++ ( int )
{
Date tmp = * this ;
* this += 1 ;
return tmp;
}
Date& Date:: operator -= ( int day)
{
if ( day < 0 )
{
* 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)
{
Date tmp ( * this ) ;
* this -= day;
return tmp;
}
Date& Date:: operator -- ( )
{
* this -= 1 ;
return * this ;
}
Date Date:: operator -- ( int )
{
Date tmp = * this ;
* this -= 1 ;
return tmp;
}
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)
{
++ min;
++ n;
}
return n * flag;
}
ostream& operator << ( ostream& out, const Date& d)
{
out << d. _year << "年" << d. _month << "月" << d. _day;
return out;
}
istream& operator >> ( istream& in, const Date& d)
{
in >> d. _year >> d. _month >> d. _day;
return in;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
希望读者们多多三连支持
小编会继续更新
你们的鼓励就是我前进的动力!
id="blogVoteBox" style="width:400px;margin:auto;margin-top:12px" class="blog-vote-box"> class="vote-box csdn-vote" style="opacity: 1;">
class="pos-box pt0" style="height: 274px; visibility: visible;">
id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"> class="blog_extension blog_extension_type2" id="blog_extension">
class="extension_official" data-report-click="{"spm":"1001.2101.3001.6471"}">
class="blog_extension_card_cont">
欢迎交流~长期互三互推交流可加v
class="blog_extension_card_cont_r">
微信名片
评论记录:
回复评论: