c++ - 运算符重载实践 -日期类


前言

通过运算符重载来实现日期的各种运算。

日期类实现

一、需要实现重载的运算符

+=+、 前置++、后置++-=-、 前置--、 后置--><>=<===!=<<>>
class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month);

	//判断日期是否符合
	bool DateIsMatched(int year,int month, int day);
	
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	// 拷贝构造函数
 // d2(d1)
	Date(const Date& d);

	// 赋值运算符重载
 // d2 = d3 -> d2.operator=(&d2, d3)
	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);

	//友元函数
	//输入
	friend  istream& operator>>(istream& ist, Date& d);
	//输出
	friend  ostream& operator<<(ostream& ost, Date& d);

private:
	int _year;	//年
	int _month;	//月
	int _day;	//日
};

二、实现

1、获取某年某月的天数
用一个静态数组去记录不同月份的天数,这样就不需要多次初始了,又因为不同年份的不同月的天数是可能不一样的所以我们要进行筛选,如润年的2月份。

实现:

//获取天数
int Date::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];
	//判断是否是润年且为2月
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		day += 1;
	}
	return day;
}

2、判断我们输入的日期是否正确
当我们采用输入日期时,可能会输入一些错误的日期,如13月、32日等。

实现:

//判断日期是否符合
bool Date::DateIsMatched(int year, int month, int day)
{
	//获取当年当月的天数
	int tmp = GetMonthDay(year, month);
	
	//判断是否符合
	return month > 0 && month < 13 && day > 0 && day < tmp + 1;
}

3、实现构造、拷贝、析构成员函数
(1)构造函数
通过传递年月日来初始化这个日期类。如果没有就采用默认的缺省值。

实现:

// 全缺省的构造函数
Date::Date(int year , int month , int day)
{
	//赋值
	_year = year;
	_month = month;
	_day = day;
}

(2)拷贝构造
因为没有涉及到申请动态空间,所以用浅拷贝即可。

实现:

// 拷贝构造函数
 // d2(d1)
//因为没有动态申请的空间需要处理,只需要浅拷贝 
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

当然这里直接不写也是可以的,那样就用编译器自动生成的。

(3)析构函数
因为没有涉及到资源清理,所以这里用编译器自动生成的即可。

4、重载 << 运算符
通过友元函数去实现对 << 的重载,从而可以直接输出日期。

实现:

//输出
ostream& operator<<(ostream& ost, Date& d)
{
	//输出成员变量
	ost << d._year << "-" << d._month << "-" << d._day << endl;
	
	//使其可以连续的使用cout
	return ost;
 }

5、重载 >> 运算符
通过友元函数去实现对 >> 的重载,从而可以直接输入日期,输入完还需要判断输入的日期是否是正确的,如果不正确就需要重新输入,这里用goto语句去跳转到输入的位置。

实现:

//输入
istream& operator>>(istream& ist, Date& d)
{
again:
	//输入成员变量
	ist >> d._year >> d._month >> d._day;

	//是否会输入出现错误
	if (!d.DateIsMatched(d._year, d._month, d._day))
	{
		cout << "输入的日期有误,请重新输入" << endl;
		goto again;
	}
	//使其可以连续的使用cin
	return ist;
}

6、重载 = 运算符
因为没有涉及到申请动态空间,赋值时用浅拷贝即可。

实现:

// 赋值运算符重载
 // d2 = d3 -> d2.operator=(&d2, d3)
//因为没有动态申请的空间需要处理,只需要浅拷贝
Date& Date::operator=(const Date& d)
{
	//赋值
	_year = d._year;
	_month = d._month;
	_day = d._day;

	return *this;
}

当然这里不写用编译器自动生成的也可以。

7、重载 += 运算符
这里的是将天数加到日期上来。
(1)我们首先要判断天数加上原本的日是否大于本月的天数,不大于将天数加到原来的日上即可。
(2)当天数加上原本的日大于本月的,天数也要相应的去减,并将日置为1,月要+1,,当月大于12时,年就要+1,最后再将剩下的天数加到本月上就是最后的日期了。

实现:

// 日期+=天数
Date& Date::operator+=(int day)
{
	if(day < 0)
	{
		return *this -= -day;
	}
	//获取当月
	int tmp = GetMonthDay(_year, _month);

	//当 day + _day > tmp 时说明可以加到下个月
	while (day + _day > tmp)
	{
		//减掉加的
		day -= (tmp - _day + 1);
		//加到月初 1 号
		_day = 1;
		_month++;
		//month > 12 年+1
		if (_month > 12)
		{
			_month = 1;
			_year++;
		}
		tmp = GetMonthDay(_year, _month);
	}
	//加剩下的
	_day += day;
	 return *this;
}

8、重载 + 运算符
不改变原本的日期,将天数到日期上并返回。
这里可以直接利用上面的 += 运算符,直接实现日期+天数。

实现:

// 日期+天数
Date Date::operator+(int day)
{
	//先保存原来的
	Date d(*this);
	d += day;
	
	//返回副本
	return d;
}

9、重载 前置++后置++ 运算符

(1)前置++
就是在日期上加一天,所以我们可以直接用 += 运算符,+= 1 即可。

实现:

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

	return *this;
	}

(2)后置++
后置++和前置++的区别就是,再 +1 后需要返回没加时的日期,所以这里用一个副本先保存原来的日期再 +1 即可。

实现:

// 后置++
Date Date::operator++(int)
{
	//保存当前日期
	Date t = *this;
	*this += 1;
	
	return t;
}

10、重载 -= 运算符

日期减去天数。
(1)当月的日大于天数,直接减去就是新的日期了。
(2)当月的日小于天数,天数需要减去当月的日,月就需要 -1 ,当月小于1时年就需要 -1,然后日需要重新更新为当月的日,以此循环,直到出现日大于天数的情况,最后直接减去就是新的日期了。

实现:

// 日期-=天数
Date& Date::operator-=(int day)
{
	if(day < 0)
	{
		return *this += -day;
	}
	//日数大于天数结束
	while (_day - day <= 0)
	{
		day -= _day;
		//月的改变
		_month--;
		if (_month == 0)
		{
			_month = 12;
			_year--;
		}
		//更新日
		_day = GetMonthDay(_year, _month);
	}
	//最后减去天数
	_day -= day;

	return *this;
}

11、重载 - 运算符
不改变原来日期,返回日期减天数的日期。
先拷贝一个副本,再对副本进行操作 ,这里可以直接利用 -= 运算符实现。

实现:

// 日期-天数
Date Date::operator-(int day)
{
  //拷贝一个副本
	Date p(*this);
	p -= day;
	
	return p;
}

12、重载 前置--后置-- 运算符

(1)前置 --
直接利用 -= 1 即可。

实现:

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

	return *this;
}

(2)后置--
后置--和前置--的区别就是,再 -1 后需要返回没减时的日期,所以这里用一个副本先保存原来的日期再 -1 即可。

实现:

// 后置--
Date Date::operator--(int)
{
	//保存当前日期
	Date t = *this;
	*this -= 1;

	return t;
}

13、重载 > 运算符
规则:年份大的大,年份一样看月份,月份大的大,月份一样最后日。
通过简单的逻辑判断即可。

实现:

// >运算符重载
bool Date::operator>(const Date& d)
{
	//年
	if (_year > d._year)
	{
		return true;
	}
	else if (_year < d._year)
	{
		return false;
	}
	else//月
	{
		if (_month > d._month)
		{
			return true;
		}
		else if (_month < d._month)
		{
			return false;
		}
		else //日
		{
			if (_day > d._day)
			{
				return true;
			}
		}
	}

	return false;
}

14、重载 == 运算符
直接判断年、月、日是否相等即可。

实现:

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

15、重载 >= 运算符
借助重载的 > 、== 运算符实现即可。

实现:

// >=运算符重载
bool Date::operator >= (const Date& d)
{
	return *this > d || *this == d;
}

16、重载 < 运算符
借助重载的 >= 运算符即可

实现:

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

17、重载 <= 运算符
借助重载 < == 运算符即可

实现:

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

18、重载 != 运算符
判断年月日有一个不用即为真,否则为假。

实现:

// !=运算符重载
bool Date::operator != (const Date& d)
{
	return  _year != d._year || _month != d._month || _day != d._day;
}

19、重载 - 运算符
日期减日期返回间隔的天数。
可以先找到小的日期,再将小的日期不断+1,直到两个日期相等,即可找到相隔的天数了。

实现:

// 日期-日期 返回天数
int Date::operator-(const Date& d)
{	
//记录天数
	int sum = 0;

	//假设 d1 大于 d2 ,用拷贝不修改原来的日期
	Date d1 = *this;
	Date d2 = d;
	int flag = 1;
	//修正
	if (*this < d )
	{
		d1 = d;
		d2 = *this;
		flag = -1;
	}
	while (d2 < d1)
	{
		d2++;
		sum++;
	}
	return sum * flag;
}

20、代码总览
Date.h

#pragma once
#include<iostream>
using namespace std;

class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month);

	//判断日期是否符合
	bool DateIsMatched(int year,int month, int day);
	
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	// 拷贝构造函数
 // d2(d1)
	Date(const Date& d);

	// 赋值运算符重载
 // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);
	// 日期+=天数
	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);

	//友元函数
	//输入
	friend  istream& operator>>(istream& ist, Date& d);
	//输出
	friend  ostream& operator<<(ostream& ost, Date& d);

private:
	int _year;	//年
	int _month;	//月
	int _day;	//日
};

Date.cpp

//获取天数
int Date::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];
	//判断是否是润年且为2月
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		day += 1;
	}
	return day;
}

//判断日期是否符合
bool Date::DateIsMatched(int year, int month, int day)
{
	//获取当年当月的天数
	int tmp = GetMonthDay(year, month);

	//是否符合
	return month > 0 && month < 13 && day > 0 && day < tmp + 1;
}

//输出
ostream& operator<<(ostream& ost, Date& d)
{
	//输出成员变量
	ost << d._year << "-" << d._month << "-" << d._day << endl;
	
	//使其可以连续的使用cout
	return ost;
 }

//输入
istream& operator>>(istream& ist, Date& d)
{
again:
	//输入成员变量
	ist >> d._year >> d._month >> d._day;

	//是否会输入出现错误
	if (!d.DateIsMatched(d._year, d._month, d._day))
	{
		cout << "输入的日期有误,请重新输入" << endl;
		goto again;
	}
	//使其可以连续的使用cin
	return ist;
}

// 全缺省的构造函数
Date::Date(int year , int month , int day)
{
	//赋值
	_year = year;
	_month = month;
	_day = day;
}

// 拷贝构造函数
 // d2(d1)
//因为没有动态申请的空间需要处理,只需要浅拷贝 
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

// 赋值运算符重载
 // d2 = d3 -> d2.operator=(&d2, d3)
//因为没有动态申请的空间需要处理,只需要浅拷贝
Date& Date::operator=(const Date& d)
{
	//赋值
	_year = d._year;
	_month = d._month;
	_day = d._day;

	return *this;
}

// 析构函数
Date::~Date()
{
	//因为没有资源需要清理,所以这里不写也行
}

// 日期+=天数
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}

	//获取当月
	int tmp = GetMonthDay(_year, _month);

	//当 day + _day > tmp 时说明可以加到下个月
	while (day + _day > tmp)
	{
		//减掉加的
		day -= (tmp - _day + 1);
		//加到月初 1 号
		_day = 1;
		_month++;
		//month > 12 年+1
		if (_month > 12)
		{
			_month = 1;
			_year++;
		}
		tmp = GetMonthDay(_year, _month);
	}
	//加剩下的
	_day += day;
	 return *this;
}

// 日期+天数
Date Date::operator+(int day)
{
	//先保存原来的
	Date d(*this);
	d += day;

	return d;
}

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

	return *this;
}
// 后置++
Date Date::operator++(int)
{
	//保存当前日期
	Date t = *this;
	*this += 1;
	
	return t;
}

// 后置--
Date Date::operator--(int)
{
	//保存当前日期
	Date t = *this;
	*this -= 1;

	return t;

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

	return *this;
}

// 日期-天数
Date Date::operator-(int day)
{
	//拷贝一个副本
	Date p(*this);
	p -= day;
	
	return p;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}

	//日数大于天数结束
	while (_day - day <= 0)
	{
		day -= _day;
		//月的改变
		_month--;
		if (_month == 0)
		{
			_month = 12;
			_year--;
		}
		//更新日
		_day = GetMonthDay(_year, _month);
	}
	//最后减去天数
	_day -= day;

	return *this;
}

// >运算符重载
bool Date::operator>(const Date& d)
{
	//年
	if (_year > d._year)
	{
		return true;
	}
	else if (_year < d._year)
	{
		return false;
	}
	else//月
	{
		if (_month > d._month)
		{
			return true;
		}
		else if (_month < d._month)
		{
			return false;
		}
		else //日
		{
			if (_day > d._day)
			{
				return true;
			}
		}
	}

	return false;
}
// ==运算符重载
bool Date::operator==(const Date& d)
{
	return  _year == d._year && _month == d._month && _day == d._day;
}
// >=运算符重载
bool Date::operator >= (const Date& d)
{
	return *this > d || *this == d;
}

// <运算符重载
bool Date::operator < (const Date& d)
{
	return !(*this >= d);
}
// <=运算符重载
bool Date::operator <= (const Date& d)
{
	return *this<d || *this == d;
}
// !=运算符重载
bool Date::operator != (const Date& d)
{
	return  _year != d._year || _month != d._month || _day != d._day;
}

// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	//记录天数
	int sum = 0;

	//假设 d1 大于 d2 ,用拷贝不修改原来的日期
	Date d1 = *this;
	Date d2 = d;
	int flag = 1;
	//修正
	if (*this < d)
	{
		d1 = d;
		d2 = *this;
		flag = -1;
	}
	while (d2 < d1)
	{
		d2++;
		sum++;
	}
	return sum * flag;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值