日期类的实现

上一篇《类和对象二》中讲到了重载运算符。本篇文章用重载运算符的使用方法,实现日期类,就是写一个简单的日期计算器,精华在于运算符的重载和对已经定义好的符号的复用。

我们将声明放在类中,定义放在另一个源文件中,实现声明和定义的分离。

目录

1. 两个日期相互比较

1.1 ‘==’重载

声明

定义

注意

1.2 ‘<’重载

声明

定义

1.3 ‘<=’重载

声明

 用复用的定义

1.4 ‘>’重载

声明

定义

1.5 ‘>=’重载

声明

 定义

 1.6 ‘!=’重载

声明

 定义

2. 赋值 ‘=’重载

声明

定义

3. 对日期天数进行计算

确定月份天数

声明

定义

判断是否是闰年

定义

3.1 日期加天数 ‘+’的重载

声明

 定义

小拓展

3.2 日期加天数 ‘+=’的重载

声明

定义

3.3 +和+=相互复用定义比较 

复用+定义+=

 复用+=定义 +

到底谁复用谁效果更好呢?

3.4 日期减天数‘-=’的重载

声明

定义

3.5  日期减天数‘-’的重载

声明

用复用 -= 定义 -

4.日期 ++ 和 ++ 

4.1 ++

直接在类中定义

4.2 --

5. 求日期差,返回天数

声明

思路

第一思路:

第二思路:

定义

Date.h

Date.cpp


1. 两个日期相互比较

1.1 ‘==’重载

声明

	// ==运算符重载
	bool operator==(const Date& d);

定义

//这里隐含参数为this指针
bool Date::operator==(const Date& d)
{
	return _year == d._year&&
		_month == d._month&&
		_day == d._day;
}

注意

上述定义中为什么要加上 Date::日期类的实现_第1张图片

 下面我们写其他重载是,也要在 operator 前面指向类域:

日期类的实现_第2张图片

1.2 ‘<’重载

声明

	// <运算符重载
	bool operator < (const Date& d);

定义

要考虑到年小于、年等于月小于、年月相同天小于,这三种情况

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

1.3 ‘<=’重载

声明

	// <=运算符重载
	bool operator <= (const Date& d);

 用复用的定义

一行搞定,< 和 == 的重载我们已经写过了,在这里我们可以直接使用他们,会方便好多,不需要我们再次将冗余的代码写一次并再次判断逻辑。

bool Date::operator <= (const Date& d)
{

	return *this < d || *this == d;
}

1.4 ‘>’重载

声明

	// >运算符重载
	bool operator>(const Date& d);

定义

日期类的实现_第3张图片

直接用复用我们已经写过的 <= :

bool Date::operator>(const Date& d)
{

	return !(*this <= d);
}

1.5 ‘>=’重载

声明

	// >=运算符重载
	inline bool operator >= (const Date& d);

 定义

直接复用 > 和 == :

bool Date::operator >= (const Date& d)
{

	return *this > d || *this == d;
}

或者复用 < :

bool Date::operator >= (const Date& d)
{

	return !(*this < d);
}

 1.6 ‘!=’重载

声明

	// !=运算符重载
	bool operator != (const Date& d);

 定义

复用 == ,取反即可:

bool Date::operator != (const Date& d)
{

	return !(*this == d);
}

2. 赋值 ‘=’重载

声明

	// 赋值运算符重载
	// d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);

定义

返回的就是Date类型,就好比有两个整型变量: a=b ,返回的类型也是整型

为什么要加引用呢?

a.this指针出了函数作用域会销毁,但是this所指向的内容是不会销毁的,因此我们可以考虑使用引用返回

b. 并且如果不用引用返回,同类型的对象传值传参会调用拷贝构造,减少开销,也推荐使用引用返回

Date& Date::operator=(const Date& d)
{
	if (*this != d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}

3. 对日期天数进行计算

对日期进行计算:

比如加上天数减去天数,会涉及到月份或年的增加或减少问题。这里就需要判断天数是否超过当前对应月份天数的限制,月份是否超过12等等。并且对于特殊的2月,我们还需区分闰年和平年。

确定月份天数

声明

最后返回的是天数

	int GetMonthDay(int year, int month);

定义

//Leapyear(year) 是bool类型,判断是否是闰年

int Date::GetMonthDay(int year, int month)
{

    在这里对年和月份进行判定
	assert(year >= 0 && month>0 && month<13);

	static int MDay[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	if (month == 2 && Leapyear(year))
	{
		return 29;
	}
	else
	{
		return MDay[month];
	}
}

这里要注意为什么在数组前加上 static ,不加也是可以的,但是每次创建时调用此函数,都会开辟出新数组,static 可以保持此数组只初始化一次,使用时再次调用即可,可降低开销,提高效率。

判断是否是闰年

定义

我们直接将此函数在类中定义,将默认他是内联函数: 

	bool Leapyear(int year)
	{
		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

3.1 日期加天数 ‘+’的重载

声明

	// 日期+天数
	Date operator+(int day);

 定义

这里首先要用到拷贝构造,创建一个临时的日期类,对临时的进行更改,最后返回,就比如 a+3后,a 是不改变的。a = a+3,a才会改变。这里的运算相当于a+3

要考虑天数过大时,边界问题,天数有边界,月份有边界,超过月份的天数限制,月份+1,月份==13时,年+1

按照此逻辑进项实现:

Date Date::operator+(int day)
{
	Date ret(*this);
	ret._day += day;
	while (ret._day>GetMonthDay(ret._year,ret._month))
	{
		ret._day -= GetMonthDay(ret._year, ret._month);
		ret._month++;
		if (ret._month == 13)
		{
			ret._year++;
			ret._month = 1;
		}
	}
	return ret;
}

小拓展

当一个对象取初始化另一个不存在的对象时,调用的是构造拷贝

只有两个存在的对象使用=时,才是赋值

日期类的实现_第4张图片

 日期类的实现_第5张图片

3.2 日期加天数 ‘+=’的重载

相当于 a=a+b ,a本身会改变

声明

	// 日期+=天数
	Date& operator+=(int day);

定义

和+的逻辑相同,只不过是直接修改 this 指向的内容,注意这里的返回值与 + 不同,+ 返回的是临时变量,用传值,而这里this会销毁,  *this 不会销毁,直接返回 *this即可,返回它本身用引用返回。

判断day为负的情况,复用 -=

+=负值等价于-=正值:

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

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

3.3 +和+=相互复用定义比较 

复用+定义+=

简便很多

Date& Date::operator+=(int day)
{

	*this = *this + day;
	return *this;
}

 复用+=定义 +

+= 不复用+来实现,那么+就可以复用 +=来实现

Date Date::operator+(int day)
{
	Date ret(*this);
	ret += day;
	return ret;
}

到底谁复用谁效果更好呢?

日期类的实现_第6张图片分别调用两种方式的+和+=

由拷贝构造的次数来看,+ 复用 += 效率会更高一些。

由此推出:- 复用 -= 效率会更高。

3.4 日期减天数‘-=’的重载

声明

	// 日期-=天数
	Date& operator-=(int day);

定义

这里特别要注意的是当月份为0,时,重置月份,更新天数的时候,用更新后的月份来计算。

最后返回*this,不会销毁,用引用返回。

判断day为负的情况,复用 +=

-=负值等价于+=正值:

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

	_day -= day;
	while (_day<=0)
	{
		_month--;
		if (_month==0)
		{
			_month = 12;
			_year--;
		}

	    //月份给的是前一个月,而不是原来的月份
	    _day += GetMonthDay(_year,_month);
	}

	return *this;
}

3.5  日期减天数‘-’的重载

声明

	// 日期-天数
	Date operator-(int day);

用复用 -= 定义 -

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

4.日期 ++ 和 ++ 

4.1 ++

++运算符重载分为前置++和后置++,他们的函数形式如下:

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


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

函数名相同,为了区分开来,语法规定:

没有参数的为前置++

有参数的为后置++

直接在类中定义

前置++,直接改变*this的内容

后置++,*this不变,返回的是此函数中构建好的临时变量,临时变量进行运算操作之后返回

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

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

4.2 --

和++同理,直接在类中定义:

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

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

5. 求日期差,返回天数

两个日期不相等时,求他们之间相差多少天

声明

	// 日期-日期 返回天数
	int operator-(const Date& d);

思路

第一思路:

年之间比较求差,月之间比较求差,天之间比较球差,最后判断对应天数,累加即可。

缺点:分别判断,分别计算,过程太繁琐

第二思路:

首先判断谁大谁小,让小的开始累加,直到和大的相等为止,只需要计加了多少天即可。 

定义

这里flag来确定正负,如果现在和未来比,天数是正的,加上天数即可和大的相等

如果是现在和过去比,天数是负的,现在+天数等于过去的时间

int Date::operator-(const Date& d)
{

	int flag = 1;
	Date max = *this;
	Date min = d;
	if (*this

Date.h

#define _CRT_SECURE_NO_WARNINGS
#pragma once

#include 
#include 
using std::cout;
using std::cin;
using std::endl;

class Date
{
public:

	// 获取某年某月的天数
	bool Leapyear(int year)
	{
		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	int GetMonthDay(int year, int month);


	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		if (year < 1900 ||

			month < 1 || month > 12 ||

			day < 1 || day > GetMonthDay(year, month))

		{
			cout << "非法日期" << endl;
		}
		_year = year;

		_month = month;

		_day = day;
	}



	 拷贝构造函数
	// d2(d1)
	Date(const Date& d)
	{
		cout << "构造拷贝" << endl;
		_year = d._year;

		_month = d._month;

		_day = d._day;
	}



	// 赋值运算符重载

	// 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++()
	{
		*this += 1;
		return *this;
	}

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



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

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

	// >运算符重载
	bool operator>(const Date& d);



	// ==运算符重载
	bool operator==(const Date& d);



	// >=运算符重载
	inline 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);

	void SetDate(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

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

Date.cpp

#define _CRT_SECURE_NO_WARNINGS


#include "Date.h"

// 赋值运算符重载

// d2 = d3 -> d2.operator=(&d2, d3)

Date& Date::operator=(const Date& d)
{
	cout << "赋值" << endl;
	if (*this != d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}



 析构函数
//
//~Date()




// 日期+=天数

Date& Date::operator+=(int day)
{
	if (day<0)
	{
		return *this -= -day;
	}
	_day += day;
	while (_day>GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
	//*this = *this + day;
	//return *this;
}

// 日期+天数
Date Date::operator+(int day)
{
	Date ret(*this);
	//ret._day += day;
	//while (ret._day>GetMonthDay(ret._year, ret._month))
	//{
	//	ret._day -= GetMonthDay(ret._year, ret._month);
	//	ret._month++;
	//	if (ret._month == 13)
	//	{
	//		ret._year++;
	//		ret._month = 1;
	//	}
	//}
	ret += day;
	return ret;
}



// 日期-天数

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



// 日期-=天数

Date& Date::operator-=(int day)
{
	if (day<0)
	{
		return *this += -day;
	}
	_day -= day;
	while (_day<=0)
	{
		_month--;
		if (_month==0)
		{
			_month = 12;
			_year--;
		}
		//月份给的是前一个月,而不是原来的月份
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}


// >运算符重载

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


// ==运算符重载

//参数:看运算符来定:两个相比较,那么就有两个形参
//返回值:看运算后的结构,比较相等返回真假即可,即bool

//这里隐含参数为this指针
bool Date::operator==(const Date& d)
{
	return _year == d._year&&
		_month == d._month&&
		_day == d._day;
}



// >=运算符重载

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



// <运算符重载

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



// <=运算符重载

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



// !=运算符重载

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



// 日期-日期 返回天数

int Date::operator-(const Date& d)
{
	int flag = 1;
	Date max = *this;
	Date min = d;
	if (*this= 0 && month>0 && month<13);
	static int MDay[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	if (month == 2 && Leapyear(year))
	{
		return 29;
	}
	else
	{
		return MDay[month];
	}
}

你可能感兴趣的:(C++笔记,gnu,服务器)