用于打印日期类

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. 传参时要特别注意,运算符有几个操作数,就传几个参数this指针也算在参数中
    所以这里默认<左边的对象是用this指针传过去了,右边的对象引用传参(加const避免被传的数值被修改,引用传参提高效率)
  2. 这里的运算符重载函数是成员函数

在这里插入图片描述

调试状态下,转到反汇编比较可以观察到,两种写法的底层代码是一样的,说明了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"}">

注意在类内要添加友元的声明,在类外定义运算符重载函数时,要传两个参数,原因在于非成员函数没有隐含的 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"}">

大于的运算符重载和小于的同理,修改符号即可

但是这样写实在是太麻烦了,根据上面写的==的运算符重载>=运算符重载<运算符重载,可以极大的简化和日期类比较有关的函数

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"}">

因为我们是在原本的日期上操作,所以是+=引用返回,而不是+,注意加上负数等同于减去正数,也可以用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"}">

那么真正的日期+天数,应该是不会修改原来的日期的,而是以另一个变量返回,所以这里就可以利用拷贝构造,将一个新的日期返回,注意不能引用返回,因为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"}">

+=的写法其实大差不差,注意减去负数就是加上正数

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"}">

后置++需要提前保存值,因为是先使用再++

🔥值得注意的是:

  1. 前置++后置++虽然是运算符重载,但是形式上也构成函数重载
  2. 后置++增加这个int参数不是为了接受具体的值仅仅是占位,跟前置++构成重载
  3. 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"}">

这里最妙的是这个flag,能够刚好体现出计算的正负,虽然这种方式没有上面那种来的快,但是这种程度的差距对于计算机来说其实是可以忽略不计的

2.5 日期的输入输出

基本数据类型基于cout和cin的使用能够很方便的进行输入输出的操作,那么日期依托于运算符重载也能达到此类效果,coutcin分别属于iostram库里的ostreamistream

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"}">
  • 1
  • 2
  • 3
  • 4
  • 5

既然不能写成成员函数,那就在类外写成非成员函数,就可以带入两个参数,cout<就会转化成operator<<(cout,d1),符合书写情况

🔥值得注意的是:

  1. cout从左往右连续输出,所以要返回ostream类型才能连续输出
  2. 类外访问私有变量使用友元函数就能解决
  3. 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"}">
  • 1
  • 2
  • 3
  • 4
  • 5

同理,流输入也是同样的格式

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;
	}
 // d2(d1)

	//打印日期
	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

//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;
}

//2.>的运算符重载
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);
}

//3.=的运算符重载
///*void operator=(const Date& d)
//{
//	_year = d._year;
//	_month = d._month;
//	_day = d._month;
//}*/
//Date& Date::operator=(const Date& d)
//{
//	if (this != &d)
//	{
//		_year = d._year;
//		_month = d._month;
//		_day = d._day;
//	}
//	return *this;
//}

//4.==的运算符重载
bool Date::operator==(const Date& x)
{
	return _year == x._year
		&& _month == x._month
		&& _day == x._day;
}

//5.<=的运算符重载
bool Date::operator<=(const Date& x)
{
	return *this < x || *this == x;
}

//6.>=的运算符重载
bool Date::operator>=(const Date& x)
{
	return !(*this < x);
}

//7.!=的运算符重载
bool Date::operator!=(const Date& x)
{
	return !(*this == x);
}

//8.+=的运算符重载
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		*this -= -day;
	}
	//*this = *this + day;
	//return *this;
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			++_year;
			_month = 1;
		}
	}
	return *this;
}

//9.+的运算符重载
Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp += day;

	return tmp;

	/*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;*/
}

//10.前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

//11.后置++
Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}

//12.-=的运算符重载
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;
}

//13.-的运算符重载
Date Date::operator-(int day)
{
	Date tmp(*this);
	*this -= day;
	return tmp;
}

//14.前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

//15.后置--
Date Date::operator--(int)
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}

//16.日期-日期
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;
}

//17.输出日期
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day;
	return out;
}

//18.输入日期
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"> 微信名片
注:本文转载自blog.csdn.net的DARLING Zero two♡的文章"https://blog.csdn.net/Zero_VPN/article/details/145329738"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。

评论记录:

未查询到任何数据!