日期类超详解(c++入门)

日期类超详解(c++入门)_第1张图片

     太阳虽远,但必有太阳。

————七堇年《被窝是青春的坟墓》


 (如有不足,望留言,定改正)

    今天要向各位小伙伴们介绍的是c++入门必学之一的日期类

    在日常的生活中,日期对于我们来说是密不可分的,比如说工作上的时限,学业上的安排,对此,日期的计算就显得尤为重要了。(废话不多说)今天我们就来实现一个简易的日期计算器。(⬇️ ⬇️ )

日期类超详解(c++入门)_第2张图片

   方法:通过自定义一个日期类可以来实现简易的日期计算器。

  第一步:我们要定义一个日期类,包括了成员函数声明成员变量定义(在头文件中实现)。

  第二步:我们要定义成员函数

  第三步:对成员函数进行测试和优化

  根据我们要实现的功能: 

 1.可以输入一个合法的日期(若没有输入,则进行默认赋值)        

 2.在日期上加上一定的天数(减少一定的天数)

 3.将两个日期进行比较以及加减

  先上手自定义一个日期类,代码⬇️ ⬇️ (头文件):

#pragma once
#include

using std::cout;
using std:: endl;
using std::cin;

class Date
{
public:
    //定义构造函数
	Date(int year = 0, int month = 1, int day = 1);
    //打印日期
	void Print();
	//运算符重载
	Date operator+(int day);
	Date operator-(int day);

	Date& operator+=(int day);
	Date& operator-=(int day);

	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);

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

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

    int operator-(Date d);//计算两个日期的差值

private:
	int _year;
	int _month;
	int _day;
};

  1.可以输入一个合法的日期(若没有输入,则进行默认赋值)        

  自定义构造函数

  对于这类默认成员函数,我们一般把它写成全缺省形式

  代码⬇️ ⬇️ (GetMonthDay函数和构造函数):

//多次使用,写成内联函数
inline int GetMonthDay(int year,int month)
{
	//用static来创建变量(将变量存放到静态区),防止多次调用该函数时创建大量栈帧,消耗大
	static int _monthArray[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

	int day = _monthArray[month];
	//先进行month的判断,因为运算中除法的效率是最低的

	if (month == 2 && (year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
	{
		 day = 29;
	}
	return day;
}

Date::Date(int year , int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	//要判断输入的日期是否合法
		if (year<0||month <= 0 ||month >= 13 || day<=0 || 
            day > GetMonthDay(_year, _month))
		{
			printf("非法日期,请重新输入\n");
			exit(-1);
		}
}

  在构造函数中,我们写入一个判断,当输入的数据不符合规则时,我们就将程序终止。

注意❗️ ❗️ 

这里要对日期进行判断时,有一个天数要求:不能超过当月的天数。

所以这里我们就要定义一个GetMonthDay的函数来获得月天数。 

细节优化: 

 (1).对于GetMonthDay函数,我们将它写成内联函数,因为我们后面还会多次 调用它。

 (2).创建_monthArray数组时,我们要使用static,将它放到静态区。避免多次调用创建大量栈帧,消耗过大。

 (3).关于闰年的判断,我们要将month==2这个条件前置,因为在运算过程中法的效率较低


 2.在日期上加上一定的天数(减少一定的天数)

  (1).对+=和-=进行重载

  代码⬇️ ⬇️ :

//减少拷贝构造带来的消耗
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		*this -= -day;
	}
	else {
	_day += day;
	//判断天数是否超越了当月的天数
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		//判断月数是否超过了12
		if (_month > 12)
		{
			_year++;
			_month = 1;
		}
	}
}
	return *this;
}


//减少拷贝构造带来的消耗
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		*this += -day;
	}
	else {
	_day -= day;
	//判断天数是否小于0
	while (_day <= 0)
	{
		//判断月数是否等于一
		if (_month == 1)
		{
			--_year;
			_month = 12;
			_day += GetMonthDay(_year, _month);
		}
		else
		{
			--_month;
			_day += GetMonthDay(_year, _month);
		}
	}
}
	return *this;
}

注意❗️ ❗️

当输入的时候实参day为负数, 我们就要进行反向的运算(如加上一个负数等于减去它的相反数)。

细节优化: 

 (1).返回用传引用的方式进行(因为返回值是定义的对象,当前函数结束后它依然存在),可以避免拷贝构造,避免创建临时变量,减少消耗。

 (2).进行反向运算时,我们要学会复用已有的+=(-=)重载函数。


   (2).对+和-进行重载

  对于+(-)重载而言,它们与+=(-=)最大的区别就在于:+(-)它们不会改变原对象,即返回用传值方式;而+=(-=)它们会改变原对象,所以对于他们的返回,用传引用返回

  代码⬇️ ⬇️ :

Date Date::operator+(int day)
{
	//构造一个临时变量,避免改变对象
	Date tmp(*this);
	//直接复用+=
	tmp += day;
	//tmp._day += day;
	判断天数是否大于当月的天数
	//while (tmp._day > GetMonthDay(tmp._year, tmp._month))
	//{
	//	tmp._day -= GetMonthDay(tmp._year, tmp._month);
	//	tmp._month++;
	//	//判断月数是否大于12
	//	if (tmp._month > 12)
	//	{
	//		tmp._year++;
	//		tmp._month = 1;
	//	}
	//}
	return tmp;
}

Date Date::operator-(int day)
{
	Date tmp(*this);
	//直接复用-=
	tmp -= day;
	//tmp._day -= day;
	判断天数是否小于0
	//while (tmp._day < 0)
	//{
	//	//判断月是否为一月
	//	if (tmp._month == 1)
	//	{
	//		tmp._year--;
	//		tmp._month = 12;
	//		tmp._day += GetMonthDay(tmp._year, tmp._month);
	//	}
	//	else
	//	{
	//		tmp._month--;
	//		tmp._day += GetMonthDay(tmp._year, tmp._month);
	//	}
	//}
	return tmp;
}

细节优化: 

 充分复用+=(-=),来避免重复的代码。 


   (3).对前后自增(自减)进行重载

  对于自增(自减)的重载,我们要区分前置后置的区别。为了区分,在语法中给后置重载函数的参数加上类型。

  前置时,我们要对原对象直接进行加一(减一)操作,返回原对象;后置时,我们需要定义一个临时变量,对原对象进行加一(减一)操作,但是返回的是临时变量

  代码⬇️ ⬇️ :

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

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

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

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

细节优化: 

 (1).前置时,使用传引用返回,避免拷贝构造。

 (2).加一(减一)直接复用+=(-=)函数。


 3.将两个日期进行比较

  (1).对==进行重载

  (2).对!=进行重载

  (3).对>(<)进行重载

 (4).对>=进行重载

 (5).对<=进行重载

  这里我们采用了布尔类型,使用const避免输入型参数(传引用的d)被错误修改。

  代码⬇️ ⬇️ :

//复用>和==,来表示其他的运算符
bool Date::operator>(const Date& d)
{
	if (_year > d._year)
		return true;
	else if (_year < d._year)
		return false;
	else//_year < d._year
	{
		if (_month > d._month)
			return true;
		else if (_month < d._month)
			return false;
		else//_month < d._month
		{
			if (_day > d._day)
				return true;
			else
				return false;
		}
	}
}

bool  Date::operator<(const Date& d)
{
	return !(*this > d || *this == d);
//	if (_year > d._year)
//		return false;
//	else if (_year < d._year)
//		return true;
//	else//_year < d._year
//	{
//		if (_month > d._month)
//			return false;
//		else if (_month < d._month)
//			return true;
//		else//_month < d._month
//		{
//			if (_day < d._day)
//				return true;
//			else
//				return false;
//		}
//	}
}

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)
{
	if (_year == d._year)
	{
		if (_month == d._month)
		{
			if (_day == d._day)
				return true;
		}
	}
	return false;
}

bool  Date::operator!=(const Date& d)
{
	//复用==
	return !(*this == d);
	//if (_year == d._year)
	//{
	//	if (_month == d._month)
	//	{
	//		if (_day == d._day)
	//			return false;
	//	}
	//}
	//	return true;
}

细节优化: 

(1).形参采用了传引用的方式避免了拷贝构造

(2).学会使用复用>(<)和==来重载其他运算符


 (6).计算两个日期的差值 

  对-进行重载,使其既可以返回日期,也可以返回天数差值。

  代码 ⬇️ ⬇️ :

int Date::operator-(Date d)
{
	//定义一个变量用于计数
	int count = 0;
	//定义一个对象防止改变原对象
	Date tmp(*this);
	if (tmp < d)
	{
		while (tmp != d)
		{
			++count;
			tmp += 1;
		}
	}
	else if (tmp > d)
	{
		while (tmp != d)
		{
			--count;
			tmp -= 1;
		}
	}
	return count;
}
细节优化:

充分使用复用,减少代码量。


总结:通过对日期类的书写,可以更好地帮助我们掌握C++中一些零碎的语法,加强一些细节上的把握。同时,学习C++的过程的,我们要将C与之对比,因为C++引入的大部分都是针对C的缺陷,两相对比,我们才可以更深层次地理解二者的联系区别


日期类超详解(c++入门)_第3张图片

    勿因未侯日光暖,擅自轻言世间寒。

————三轮一言《k》

    愿与诸君共勉!

你可能感兴趣的:(C++入门语法,c++)