类和对象——日期类的实现

目录

构造函数初始化

打印函数

日期类的大小比较

> 运算符的重载

== 运算符的重载

>= 运算符的重载

< 运算符的重载

<= 运算符的重载

!= 运算符的重载

日期的运算

日期+=天数

日期+天数

日期-=天数

日期-天数

前置++

后置++

前置--

后置--

日期-日期

打印星期几


  学习了6个默认成员函数之后,我们可以完成日期类了,我们平时可能需要计算100天后是多少号?是星期几?和XXX间隔多少天?等等问题。我们就需要靠自定义类型来实现这些成员函数。

首先给出我们的成员函数和成员变量的声明

#pragma once
#include<iostream>
#include<stdbool.h>
using namespace std;
class Date
{   
public:
	Date(int year = 1, int month = 1, int day = 1);//声明
	void Print()const;//打印
	int GetMonthDay(int year, int month)const;//获取这年某月的天数

	bool operator>(const Date& d)const;//>运算符重载
	bool operator<(const Date& d)const;//<运算符重载
	bool operator==(const Date& d)const;//==运算符重载
	bool operator!=(const Date& d)const;//不等于运算符重载
	bool operator>=(const Date& d)const;//>=运算符重载
	bool operator<=(const Date& d)const;//<=运算符重载

	Date& operator+=(int day);//加等于
	Date operator+(int day)const;//加
	Date& operator-=(int day);//减等于
	Date operator-(int day)const;//减

	Date& operator++();//前置++
	Date operator++(int);//后置++
	Date& operator--();//前置--
	Date operator--(int);//后置--

	int operator-(const Date& d)const;//日期-日期
	void PrintWeekDay()const;//判断星期几
private:
	int _year;
	int _month;
	int _day;
};

构造函数初始化

首先我们遇到的问题就是,我们给定一个日期,需要判断这个日期的合理性以及存在性。

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	//判断传入时间的合法性,例如2022-13-27
	if (!(_year > 0
		&& (_month > 0 && _month < 13)
		&& (_day > 0 && _day <= GetMonthDay(_year, _month))))
	{
		cout << "非法日期:" << endl;
		Print();
	}
}
int Date::GetMonthDay(int year, int month)const//获取这年某月的天数
{
	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;
}

GetMonthDay遇到的问题: 

第一个问题就是闰年问题,我们需要获取这年这个月的天数,难免就会遇到判断闰年问题。

①可以用12个if else 语句判断我们的闰月

②可以利用switch case语句

③以上都显得代码比较冗余,由于12个月我们都是知道每个月的天数的,我们可以将这些月份数存入一个静态数组中,下标为0处,初始化为0,其余月份可以快速写上

第二个问题就是我们可以首先判断是否为二月(month==2),因为不是二月的时候就不用判断是不是闰年了

打印函数

我们直接采用标准输出即可

//打印函数
void Date::Print()const
{
	cout << _year << "-" << _month << "-" << _day << endl;
}

日期类的大小比较

需要注意的是,类的成员函数,默认第一个参数是隐藏的this指针,第二个参数是右操作数

> 运算符的重载

思路比较直接,年份大则大,年份一样比月,月大则大,月份再一样比天,天大则大

bool Date::operator>(const Date& d)const//大于
{
	if (_year > d._year)
		return true;
	else if (_year == d._year && _month > d._month)
		return true;
	else if (_year == d._year && _month == d._month && _day > d._day)
		return  true;
	else
		return false;
}

== 运算符的重载

等于意思就是,两个日期年月日都相等,那么它们两个相等

bool Date:: operator==(const Date& d)const//等于
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

>= 运算符的重载

日期需要满足大于或者等于即可

bool Date:: operator>=(const Date& d)const//大于等于
{
	return *this > d || *this == d;
}

< 运算符的重载

小于我们可以很容易想到就是,小于等于的反面

bool Date::operator<(const Date& d) const//小于
{
	return !(*this >= d);
}

<= 运算符的重载

小于等于的反面就是大于,我们也很容易想到

bool Date::operator<=(const Date& d)const//小于等于
{
	return !(*this > d);
}

!= 运算符的重载

bool Date::operator!=(const Date& d)const //不等于
{
	return !(*this == d);
}

日期的运算

日期+=天数

首先我们想到的肯定就是进位的问题了。首先将天数加到日上面,考虑日期是否合法,不合法就要考虑进位问题。

进位问题:

1、天满往月进位(如果天满了,就要减去当前月份的天数,月份加1)

2、月满往年进位(如果月满了,就要将年份加1,月份重新置为1)

返回*this:

+=是两个操作数符号,我们同样需要返回左操作数,*this其实就是d对象更新后的日期

引用返回:

为了减少值拷贝,*this其实就是d的别名,我们直接返回即可

特殊情况下,如果增加的是负的天数,我们就是 -= 当前的天数的负数

Date& Date::operator+=(int day)//加等于
{
	if (day < 0)//当day为负数时,处理一下
	{
		return *this -= -day;
	}

	_day += day;

	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}

	return *this;
}

日期+天数

+和+=的区别就是返回值的不同。

例如:d1+10不会改变d1的值,而d1+=10会改变d1的值

Date Date::operator+(int day)const//加
{
	Date ret(*this);//运用拷贝构造
	ret += day;//复用已经实现的 +=
	//实际上的编译器会这样处理 
	//ret.operator+=(day);
	return ret;
}

日期-=天数

首先我们想到的是借位问题。我们首先用日减去天数,判断日期是否合法,如果不合法就要考虑借位问题。

退位问题:

1、减出来如果日是负数,月份就-1

2、如果月份减到0了(month==0),我们就要往年借位,年-1,月份重置为12

3、最后日再加上当月的天数

特殊情况下,如果减去的是负的天数,我们就是 += 当前的天数的负数

Date& Date::operator-=(int day)//减等于
{
	if (day < 0)//当day为负数时,处理一下
	{
		return *this += -day;
	}

	_day -= day;

	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

日期-天数

-和-=的区别也是返回值的不同

我们这里要拿到的返回值就是改变之后的值

Date Date::operator-(int day)const//减
{
	Date ret(*this);
	ret -= day;
	return ret;
}

前置++和后置++,两者的最大区别就是返回值的不同,前置++返回的是加加后的值,后置++返回的是加加以前的值

C++中为了区别前置和后置操作符,我们在后置++中引入看一个参数占位符,来区分这两个函数的重载,并没有什么实际的意义

注意:后置++是需要返回加加之前的值,我们这里先用*this拷贝构造一个ret对象(实际上是保存了一份加加之前的值),由于ret对象出了作用域就会被销毁,所以不能用引用返回,只能用传参返回,相当于再次拷贝一份给Date。而前置加加就可以直接返回引用,减少拷贝。

前置++

Date& Date::operator++()//前置++,返回加加后的值
{
	*this += 1;
	return *this;
}

后置++

Date Date::operator++(int)//后置++,返回加加前的值
{
	Date ret(*this);//拷贝构造
	*this += 1;
	return ret;
}

前置--

Date& Date::operator--()//前置--
{
	Date ret(*this);//拷贝构造
	*this -= 1;
	return *this;
}

后置--

Date Date::operator--(int)//后置--
{
	Date ret(*this);//拷贝构造
	*this -= 1;
	return ret;
}

日期-日期

我们平常生活中可能需要计算一下,两个日期之间差了多少天,这里我们就可以计算了。

思路:我们可以选出较小的一个日期(将它自加1),拿它去“追赶”较大的日期,再定义一个计数变量,随着较小的日期自加而自加,追上之后就是两个天数的差值

int Date::operator-(const Date& d)const//日期-日期
{
	//我们不知道哪个日期大一点,所以假设
	Date max = *this;//先假设d1>d2
	Date min = d;
	int flag = 1;
	if (*this < d)//如果d1<d2,再交换最大值和最小值
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int count = 0;
	while (min != max)
	{
		++min;
		++count;
	}
	return count * flag;
}

打印星期几

我们生活中有时需要查找这个日期是星期几,现在就可以实现了。

思路:经过查找,我们发现1900年的1月1日恰好是星期一,我们可以将它作为时间的起点,将每个星期存入一个数组中,计算某个日期与1900-1-1之间差值,最后得到的天数模上7就可以知道是周几啦

void Date::PrintWeekDay()const
{
	const char* arr[] = { "星期一","星期二","星期三","星期四","星期五","星期六","星期日" };
	/*Date start(1900, 1, 1);
	int count = *this - start;*/
	//匿名对象
	int count = *this - Date(1900, 1, 1);
	cout << arr[count % 7] << endl;
}

谢谢观看! 

猜你喜欢

转载自blog.csdn.net/weixin_57675461/article/details/123020393