C++初阶(4)——Date日期类的具体实现

发布时间:2023-09-23 14:00

参照正规项目的写法,我们分成三个文件:

  1. Date.h——类的实现和函数声明
  2. Date.cpp——函数实现
  3. test.cpp——测试用例

我们主要实现Date.h和Date.cpp,test.cpp读者可以实际需要自行实现

Date.h

#pragma once
#include

//正规的项目写法中,只展开几个常用的函数,不展开整个命名空间
using std::cout;
using std::endl;
using std::cin;
 //本类中成员变量都是内置类型,因此析构,拷贝构造,赋值重载都可以不用写 
class Date
{
public:
	//1.构造函数
	Date(int year, int month , int day );
	
	//2.打印
	void Print() const;
	
	//3.重载+=
	Date& operator+=(int day);
	
	//4.重载+
	Date operator+(int day);
	
	//5.重载-=
	Date& operator-=(int day);
	
	//6.重载-(日期减int)
	Date operator-(int day);
	
	//7.重载前置++与后置++
	Date& operator++();
	Date operator++(int);

	//8.重载前置--与后置--
	Date& operator--();
	Date operator--(int);

	//9.重载各比较运算符
	bool operator>(const Date& d);
	bool operator==(const Date& d) const;
	bool operator>=(const Date& d);
	bool operator!=(const Date& d);
	bool operator<(const Date& d);
	bool operator<=(const Date& d);
	 
	//10.重载-(日期减日期)
	int operator-(const Date& d);
private:
	int _year;
	int _month;
	int _day;
};

Date.cpp

先编写一个提取每月天数的函数GetMonthDay,这在后面的多个函数中都有调用,故设计成内联。内联函数不支持定义和声明分离,故Date.h中没有声明该函数

#include "Date.h"

//每生成一个对象就要调用一次,故设置成内联
inline int GetMonthDay(int year,int month)
{
	//第一个给0是为了然后给月份和数组下标一一对应
	static int dayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	int day = dayArray[month];

	//对于闰年的二月特殊处理
	//对month的判断要写到前面
	if (month == 2 && (year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
	{
		day = 29;
	}

	return day;
}

1.构造函数

Date::Date(int _year, int _month, int _day)
{
	//先检查日期的合法性(假设都表示公元后)
	if (_year >= 0 && (_month > 0 && _month <= 12) && (_day > 0 && _day <= GetMonthDay(_year, _month)))
	{ 
		    this->_year = _year;
			this->_month = _month;
			this->_day = _day;
	}
	else
	{
		cout << "非法日期" << endl;
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
}

2.打印

void Date::Print() const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

这里先插一句:C++类常成员函数的写法:
返回类型 类名::函数名(变量列表) const
const对象不能调用非const成员函数,非const对象可以调用const成员函数
为为了让const对象以及非const对象都能调用Print函数,因此设计成const函数

3.重载+=
+=可以在原本对象上操作,因此返回类型设计成引用,返回 *this

Date& Date::operator+=(int day)
{
	_day += day;
	//如果天数不合法就要不断循环,直至合法
	while (_day > GetMonthDay(_year, _month))
	{
		//循环体完成进位
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month > 12)
		{
			_year += 1;
			_month = 1;
		}
	}
	return *this;
} 

4.重载+
有两种实现方式
(1)直接写

//返回的是临时变量,返回类型不能填引用
Date Date::operator+(int day)
{
	Date temp(*this);//调用拷贝构造函数实现初始化
	temp._day+= day;
	while (temp._day > GetMonthDay(temp._year, temp._month))
	{
		temp._day -= GetMonthDay(temp._year, temp._month);
		temp._month++;
		if (temp._month > 12)
		{
			temp._year += 1;
			temp._month = 1;
		}
	}
	return temp;
}

(2)采取复用
巧用复用很重要,复用可以帮助我们很大程度地精简代码

Date Date::operator+(int day)
{
	Date temp(*this);//注意这里的初始化方式
	//复用重载的+=
	temp += day;
	return temp;//临时变量不能返回

5.重载-=

Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		//循环体内部完成借位
		--_month;
		if (_month == 0)
		{
			_year -= 1;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

6.重载 -
与+一样,重载-也有两种写法
(1)不复用

Date Date::operator-(int day)
{
	Date temp(*this);
	temp._day -= day;
	while (temp._day <= 0)
	{
		--temp._month;
		if (temp._month == 0)
		{
			temp._year -= 1;
			temp._month = 12;
		}
		temp._day = GetMonthDay(_year, _month);
	}
	return temp;
}

(2)采取复用

Date Date::operator-(int day)
{
	Date temp(*this);
	temp -= day;
	return temp;
}

7.重载前置++与后置++
重载前置++和后置++是一个重难点。
前置++和后置++都完成了++,不同的地方是:返回值不一样。前置++返回++之后的对象,返回Date& ; 后置++返回++之后的对象,返回Date。但单单返回类型不一样不能实现函数重载,因此我们给两个函数不同的参数列表

前置++:Date& operator++()
后置++:Date operator++(int)
后置++中的int没有实际意义,不需要给实参

//1、前置++
Date& Date::operator++()
{
	(*this)._day += 1;
	return *this;
}
//2.后置++
Date Date::operator++(int)
{
	Date temp(*this);
	(*this)._day += 1;
	return temp;
}

8.重载前置–与后置–
与++类似:

//1.前置--
Date& Date::operator--()
{
	(*this)._day -= 1;
	return *this;
}
//2.后置--
Date  Date::operator--(int)
{
	Date temp(*this);
	(*this)._day -= 1;
	return temp;
}

9.重载各比较运算符

bool Date::operator>(const Date& d)
{
	if (this->_year > d._year)
	{
		return true;
	}
	else if (this->_year == d._year)
	{
		if (this->_month > d._month)
		{
			return true;
		}
		else if (this->_month == d._month)
		{
			if (this->_day > d._day)
			{
				return true;
			}
		}
	}

	//所有大于的情况均已罗列完毕
	return false;
}

//如果不小心把==写成了=,加const可以很快地检查出来
bool Date::operator==(const Date& d)  const
{
	return this->_year == d._year
		&& this->_month == d._month
		&& this->_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);
}

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

10.重载-(日期减日期)

//注意:千万不要直接两者相减,这样分类讨论太麻烦了
//先判断大小,再让小的不断++,直到小的与大的相等为止
int Date::operator-(const Date& d)
{
    //先假设*this是较大的那个,如果不对就交换
	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;
}

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号