Bootstrap

C++ 日期计算器的实现(运算符重载)

目录

一、前言

二、正文

1.1 Date类框架

1.2 两个日期间的直接赋值

1.3判断两个日期是否相同

1.4判断两个日期是否不同

 1.5日期加天数

1.6日期+=天数

1.7日期的前置++和后置++

1.8日期减天数

1.9自身日期减天数

2.1自身日期前置--和后置--

 2.2两个日期的差值为差距天数

2.3判断两个日期的关系(<或<=)

2.4判断两个日期的大小(>和>=)

2.5重载运算符输入>>和输出<<(>>和<<其实是流)

 三、结语


一、前言

前面我们已经分享了有关C++中运算符重载的一些相关知识,现在让我们运用这些知识写一个日期计算器吧。

二、正文

1.1 Date类框架

class Date
{
public:
Date(int year = 2024, int month = 11, int day = 20)//构造函数
{
	_year = year;
	_month = month;
	_day = day;
}
Date(const Date& d)//拷贝构造函数
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
private:
int _year;
int _month;
int _day;
};

1.2 两个日期间的直接赋值

Date& operator=(const Date& d)//两个日期之间的直接赋值拷贝
{
	_year = d._year;
	_month= d._month;
	_day = d._day;
	return *this;
}

1.3判断两个日期是否相同

	bool operator==(const Date& d)//判断两个日期是否日期相同,相同返回true,不相同返回false
	{
		return _year == d._year &&
			_month == d._month &&
			_day == d._day;
	}

1.4判断两个日期是否不同

bool operator!=(const Date& d)//判断两个日期是否相同,不相同返回true,相同返回false
{
	if (_year != d._year)
		return true;
	if (_month != d._month)
		return true;
	if (_day != d._day)
		return true;
	return false;
}

 1.5日期加天数

int CheckDayCount(int year,int month)//获得当月的天数
	{
	int Day[] = { 0,31,28,31,30,31,30,31,31,30,31,30 ,31 };
	if (month==2&&year % 4 == 0 && year % 400 == 0)
	{
		return 29;
	}
	return Day[month];
}

Date operator+(int x)//日期加天数
{
    Date tmp(*this);
	tmp._day = tmp._day + x;
	while (tmp._day > tmp.CheckDayCount(tmp._year,tmp._month))
	{
		tmp._day = tmp._day - tmp.CheckDayCount(tmp._year, tmp._month);
		tmp._month++;
		if (tmp._month == 13)
		{
			tmp._month = 0;
			tmp._year++;
		}
	}
	return tmp;
}

在日期加天数这个函数中,我们需要用到CheckDateCount这个成员函数,这个函数是输出某月的天数(比如11月返回30天,2月根据平年和闰年分别返回28,29天)。

operator+的实现原理是:我们先将要加的天数x直接加到*this的拷贝tmp中(注意这里不能改变*this的成员,就比如一个整形a,我们让它加1就是a+1,在这个a+1过程中a是没有改变的,这里我们用tmp拷贝*this就是类似这里不想改变”a“的值一样)如果tmp.day大于tmp.month所代表的的天数,这里就设为Day(这里我们是通过CheckDateCount实现返回某月天数的)

那么我们就拿tmp.day-Day,tmp.day-Day执行一次tmp.month++一次。如果tmp.month>12(一年只有12个月),那么tmp.year++,并且让tmp._month=1。

直到tmp.day<=Day,while循环结束。

例子:初始tmp._year=2024,tmp._month=11.tmp._day=20。

我们让tmp+100(x=100),tmp就有:tmp._year=2024,tmp._month=11,tmp._day=120。

第一次循环:因为tmp._day(120)>30(CheckDateCount(2024,11),11月是30天)进入while循环:

tmp.day(120)=tmp._day-30(CheckDateCount(2024,11),11月是30天)->tmp._day=90。

tmp._month++(11+1=12);

第二次循环:因为tmp._day(90)>31(CheckDateCount(2024,11),12月是31天)进入while循环:

tmp._day(90)=tmp._day-31(CheckDateCount(2024,11),12月是31天)->tmp._day(59)

tmp._month++(12+1=13)。因为tmp._month(13)>12。所以让tmp._year++(2024+1=2025)

并且让tmp._month=1。

第三次循环:  因为tmp._day(59)>31(CheckDateCount(2024,12),1月是31天)进入while循环:

tmp._day(59)=tmp._day-31(CheckDateCount(2024,1),1月是31天)->tmp._day(28)

tmp._month++(1+1=2)。

此时准备第四次循环,发现tmp._day(28)=28(CheckDateCount(2024,2),2025年是平年,所以2月是28天)不进入第四次循环,循环结束

operator+返回tmp,其中tmp._year=2025、tmp._month=2、tmp._day=28。函数结束。

1.6日期+=天数

	Date& operator+=(int x)//自身日期加天数
	{
		*this = *this + x;
		return *this;
	}

 *this=*this+x中,这个=其实是我们上面写得operator+(成员函数之间可以相互复用)

下面我们写的一些运算符重载函数中,也有一些运算符重载函数复用了其他运算符重载函数。例如我们这里operator+=就复用了operator+。

1.7日期的前置++和后置++

Date& operator++()
{
	//这里是前置++
	*this += 1;
	return *this;
}
//上下两个都是operator++,那么编译器如何分辨什么时候是前置++,
//什么时候是后置++呢
//为了区分两者,C++规定必须给后置++,强行增加一个int形参
//这个形参可以不用管它,这个参数仅仅是为了区分前置++和后置++用的,无实际意义。
Date operator++(int)
{
	//这里是后置++
	Date tmp(*this);
	*this += 1;
	return tmp;
}

1.8日期减天数

Date operator-(int x)//日期减天数:例如:d1-100
{
	Date tmp(*this);
	tmp._day = tmp._day - x;
	while (tmp._day < 0)
	{
		tmp._month--;
		if (_month == 0)
		{
			tmp._year--;
		}
		tmp._day = tmp._day + tmp.CheckDayCount(tmp._year, tmp._month);
	}
	return tmp;
}

1.9自身日期减天数

Date& operator-=(int x)//自身日期减天数 例如:d1-=100
{
	*this = *this - x;
	return *this;
}

2.1自身日期前置--和后置--

Date& operator--()//例如:--d1。
{
	//这里是前置--
	*this -= 1;
	return *this;
}
Date operator--(int)//例如:d1--。
{
	//这里是后置--
	Date tmp(*this);
	*this -= 1;
	return tmp;
}

 这里的分别前置--和后置--的区别方法和上面前置++和后置++一样。

 2.2两个日期的差值为差距天数

int operator-(const Date& d)//两个日期的差值表示差距天数 例如:d1-d2返回天数
{
	Date min = d;
	Date max = *this;
	int flag = 1;
	int count = 0;
	if (*this <= d)
	{
		 min= *this;
		 max = d;
		flag = -1;
}
	while (min!=max)
	{
		min++;
		count++;
	}
	return count*flag;
}

这个函数的思想是:我们首先假设日期*this是大于d的,则有min=d;max=*this。当*this>d

的时候,我们另flag=1表示正数(为了方便表示*this-d>0)。

反之,如果实际上,*this<=d,则另min=*this,max=d。flag=-1(为了方便表示*this-d<0)

因为min<ma=x,那么min一直累加到和max相同这个过程的次数,就是min与max的差值,即是日期*this和日期d之间相差的天数。如果*this<d输出的值就是负数。反之就是正数或是0。

这个时候我们定义的flag就是起到了表示函数返回的天数是正数还是负数的功能。

比如这里:

假设*this(2024,11,20)、d(2025,11,20)因为*this<d。所以min=*this、max=d、

flag=-1。min一直++,一直加到min=max,这个过程中min++的次数count就是min和max的差值。即也是*this和d相差的天数。这里我们返回count*flag=365*(-1)=-365。

2.3判断两个日期的关系(<或<=)

	bool operator<=(const Date& d) const//判断一个日期是否小于等于另外一个日期
	{
		return d >= *this;//这里复用了我们上面写的operator>=,通过复用就可以使代码更加简洁。
	}
	bool operator < (const Date& d) const //判断一个日期是否小于另外一个日期
	{
		return d > *this;
	}

2.4判断两个日期的大小(>和>=)

bool operator >= (const Date& d)const//判断一个日期是否大于等于另外一个日期
{
	return  _year >= d._year && _month >= d._month && _day >= d._day;
}
bool operator>(const Date& d)const// const//判断一个日期是否大于另外一个日期
{
	if (_year > d._year)
	{
		return true;
	}
	if (_month > d._month)
	{
		return true;
	}
	if (_day > d._day)
	{
		return true;
	}
	return false;
}

2.5重载运算符输入>>和输出<<(>>和<<其实是流)

ostream& operator<<(ostream& out,const Date& d)//运算符重载输出语句
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}
istream& operator>>(istream& in,  Date& d)//运算符重载输入语句
{
	cout << "请输入年月日:" << endl;
	in >> d._year >> d._month >> d._day;
	while (d._month > 12 || d._day<0 || d._day>d.CheckDayCount(d._year, d._month))
	{
			cout << "输入日期有误!" << endl;
			cout << d;
			cout << "请重新输入:" << endl;
			in >> d._year >> d._month >> d._day;
	}
	return in;
}

 上面这两个函数我们并没有定义在Date类中,而是定义在全局中。为了能在Date类外面能访问到类成员属性(_year,_month,_day)我们这里使用了友元函数的功能。

友元函数类似一个通行证,只要在类中这样表示:friend后跟类外的一个函数。这样这个类外函数就可以访问到我们的类成员属性了。

类似如下:

 三、结语

 日期计算器的实现就到这里了,帅哥美女们咱们下次再见

;