C++——日期类的实现


日期类的实现其实非常简单,不要被长长的目录吓到哦!

1.获取某年某月的天数

下面这里用一个数组代表12个月,还需要分辨一下是平年还是闰年

	int GetMonthDay(int year, int month)
	{
		static int monthDayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			return 29;
		}
		else
		{
			return monthDayArray[month];
		}
	}

2.全缺省的构造函数

这里是全缺省日期类的构造函数,下面代码还检查了一下你构造的日期是否合理。

	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;

		// 检查日期是否合法
		if (!(year >= 1
			&& (month >= 1 && month <= 12)
			&& (day >= 1 && day <= GetMonthDay(year, month))))
		{
			cout << "非法日期" << endl;
		}
	}

3.打印函数

void Print() 
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

	

4.拷贝构造函数

    // d2(d1)
	Date(const Date& d) 
	{
		_day = d._day;
		_month = d._month;
		_year = d._year;
	}

4.赋值运算符重载

下面的赋值重载自动把=左边的一个对象当作*this的对象,把右边的对象赋值给左边的对象,而且需要注意的是,赋值运算符是可以连续赋值的,我们设计函数的时候要把这一点考虑进去,返回值就要返回=左边的对象。

    // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d)
	{
		_day = d._day;
		_month = d._month;
		_year = d._year;
		return *this;
	}

5.析构函数

对于日期类,没有空间的开辟(malloc等),其实不写也是可以的,但是如果写的话,析构函数的声明和定义都要写出来否则就会报错。只有声明 ,没有实现的话 ,只要不调用,就不会报错,但是调用了就会报链接错误 ,因为编译器链接的时候找不到函数的入口地址。
如果创建对象了 ,那对象销毁的时候编译器要自动调用析构函数 ,而析构函数没有定义,那就报链接错误了。

	~Date()
	{

	}

6.日期±天数

日期+=天数

+=运算符的左操作数是this对象,

Date& Date::operator+=(int day)
{
	if (day < 0)//输入的是负值就要进行相应的转变
	{
		(*this) -= abs(day);
	}
	else//输入正值的情况
	{
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month > 12)
			{
				_year++;
				_month = 1;
			}
		}
	}
	return *this;
}

日期-=天数

Date& Date::operator-=(int day)
{
	if (day < 0)//输入的是负值就要进行相应的转变
	{
		(*this) += abs(day);
	}
	else//输入正值的情况
	{
		_day -= day;
		while (_day <= 0)
		{
			if (_month == 1)
			{
				_month = 12;
				_year--;
				_day += GetMonthDay(_year, _month);
			}
			else
			{
				_month--;
				_day += GetMonthDay(_year, _month);
			}
		}
	}
	
	return *this;
}

7.日期±天数

日期+天数

日期+天数要注意这里的返回值,重新定义一个tmp对象,把原来的*this拷贝进去,对tmp进行+=操作,返回tmp对象的值,而且返回只能是“值返回”,不能用“引用返回”,因为tmp这块空间返回之后就被销毁了。

Date Date::operator+(int day)
{
	Date tmp = (*this);//拷贝构造函数
	tmp += day;
	return tmp;
}

日期-天数

类比日期+天数即可

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

8.各种++和- -

结合C语言,前置++其实就是“先++,再使用”,所以说返回值这里要对*this++之后的值返回,具体怎么返回就看函数结束了这块空间是否还存在。

前置++

前置++其实就是对*this++,然后返回就可以了,不需要另外拷贝一份再返回。

Date& Date::operator++() 
{
	if ((_month == 12)&&(_day==31))
	{
		_year++;
		_month = 1;
		_day = 1;
	}
	else
	{
		_day++;
		if (_day>GetMonthDay(_year,_month))
		{
			_month++;
			_day = 1;
		}
	}
	
	return *this;
}

后置++

后置++结合C语言就是“先使用,再++”,就是对*this已经++了,返回值要返回没++之前的值,所以要拷贝一份原来的值,最后返回原来的值就行了。

Date Date::operator++(int)
{
	Date tmp(*this);
	++(*this);
	return tmp;
}

前置- -

返回值可以类比前置++,但是这里- -的过程可能有一丢丢复杂。

Date& Date::operator--()
{
	if (_day == 1 && _month == 1)
	{
		_month=12;
		_day = GetMonthDay(_year, _month);
		_year--;
	}
	else if (_day == 1)
	{
		_month --;
		_day = GetMonthDay(_year, _month);
	}
	else
	{
		_day--;
	}
	return *this;
}

后置- -

类比后置++即可

Date Date::operator--(int)
{
	Date tmp(*this);//拷贝构造
	--(*this);
	return tmp;
}

9.运算符重载

>运算符重载

基本逻辑:先比年,年相等了再比月,月也相等了,那就再比日。

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) && (_month == d._month) && (_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));
}

10.<<和>>运算符重载

在这里插入图片描述
从上图我们可以看到,其实cin和cout是C++内置类的两个函数,对应的类名分别是istream和ostream,对于流插入和流提取的重载值得注意的是,他俩不能在类里进行声明和定义
原因:在类里实现的话左操作数是this对象,并且这个this对象只能是类类型,正常我们cout<<d1;但是我们想在类里面实现的话,最后在类里实现完之后使用的时候要d1<<cout,所以说在类里流插入和流提取不能进行重载。这里干脆就只能把它放在类外面,弄成一个全局函数。
而且为了能满足链式访问,我们这里的函数的返回值要是istream类和ostream类的。

inline ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

inline istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

11.日期-日期(返回天数)

这里我们就用一种比较简单的方法,定义一个max和min对象,并max = *this,min = d,假设max>min则flag为1,用min++,并且计数,加一次计数器count就+1,直到min和max相等为止。相反max<min则,flag为-1,重新给min和max赋值。最后用count乘以flag就可以了。

int Date::operator-(const Date& d)
{
	int count = 0;
	Date max = *this;
	Date min = d;
	int flag = 1;
	if (min > max)
	{
		min = *this;
		max = d;
		flag = -1;
	}

	while (max!=min)
	{
		min++;
		count++;
	}
	return count * flag;
}

好啦这就是全部的讲解了。
这里是全部代码的链接:代码链接
***************************************************end ******************************************************
_______________________有哪里看不懂可以随时向博主提问 ___________________________
_______________________有错误的地方欢迎各位老铁批评指正 _________________________
***************************************************end ******************************************************
在这里插入图片描述

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有效的放假者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值