【C++】类和对象—日期类的实现

在这里插入图片描述

一、日期类的功能

实现日期类的==、!=、+=、+、-=、-、>=、>、<=、<、前置++和–、后置++和–。

二、获取月的天数

因为GetMonthDay这个函数需要在日期类中被频繁调用,所以将 monthArr存放至静态区,减少数组频繁开辟、销毁空间的开销。

先把2(代表2月)为下标的天数置为28天。判断闰年如果为闰年就把2月的天数置为29。

int Date::getMonthDay(int year, int month)
{
	assert(month < 13 && month>0);
    
    //静态数组,每次调用不用频繁在栈区创建数组
	int monthArr[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 monthArr[month];
	}
}

三、Date类中的默认成员函数

构造函数

我们需要判断日期输入是否合法,不排除有人在输入时不小心输了一个2023-10-422.这样的输入的就是错误的。需要判断日期输入是否合法

Date::Date(int year, int month, int day)
{
	//需要判断日期输入是否合法
	if (month > 0 && month < 13 && (day > 0 && day <= getMonthDay(year, month)))
	{
		_year = year;
		_month = year;
		_day = day;
	}
	else
	{
		cout << "日期非法" << endl;
	}
}

析构函数

默认生成的就够用

~Date()//可不写
{
    ;
}

拷贝构造

默认生成的拷贝构造就够用,默认拷贝会对内置类型进行浅拷贝。

Date(const Date& d)//可不写
{
    _year = d._year;
    _month = d._month;
    _day = d._day;
    //cout << "拷贝构造成功" << endl;
}

赋值运算符重载

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

也可不写,使用系统默认生成的即可。
拷贝构造和赋值运算符重载的区别在于拷贝构造用于对象构造时使用,而赋值运算符重载用于已存在对象赋值时使用
后续处理有资源的对象时,需要先把旧空间释放,再开一块同样大小的空间,进行数据拷贝。

如果忘记了可以复习一下我的上一篇复习类和对象【中】

取地址操作符重载和const取地址操作符重载

这两个函数意义不大

这两个默认成员函数一般不用重新定义 ,编译器默认会生成的就足够用了

Date* operator&()
{
    return this;
    //return nullptr;
}
const Date* operator&()const
{
    return this;
    //return nullptr;
}

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容

四、运算符重载

🌒+、+=、-、-=

日期+=天数

应该怎么办呢?
2023年4月10日 +100天,但顺着我们正常的计算思维,列写几个例子,其实很简单。✅它其实就是一个不断进位的过程,天满了往月进;月满了往年进、月归1.月满年+1,月直接重置为1.
在这里插入图片描述

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		//这里是复用的-=,后面会写
		//当日期-100时,就会复用-=
		return *this -= -day;
	}

	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;//d1没销毁,可以传引用返回
}

日期+天数

+就是不改变d1的值。
我们直接复用+=,拷贝构造一个临时变量,避免对d1的改变。

Date Date::operator+(int day)
{
	Date tmp = (*this);
	tmp += day;

	return tmp;
}

日期-=天数

在这里插入图片描述

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

		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

注:

  1. 天数 <= 0都不合法,要借位
  2. 注意我们借到的天数是上一个月的天数(这与“加”不同,“加”获取的是本月天数)
  3. 到达边界时,我们是先把月置12,再对天数处理

日期-天数

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

有的同学再写这两句代码时会报错return *this -= -day; return *this += -day;如果把这四个全都是实现就不会报错。那这是什么意思呢?
在这里插入图片描述
我们就需要判断一下
+=、+负数就去复用-=,+ (-100)就是 -= 100;
-=、 -负数就去复用 +=,- (-100)就是 +=100;

🌒==、!=、>、>=、<、<=

任何一个类,只需要写一个 > == 重载 或者 < == 即可,剩下比较运算符复用即可

//d1>d2
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)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

下面我们就开始复用

!=
bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}
//d1 >= d2
bool Date::operator>=(const Date& d)
{
	return (*this == d) || (*this > d);
}

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

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

日期-日期

//日期-日期
int Date::operator-(const Date& d)
{
	int flag = 1;//防止天数为负
	Date max = *this;//晚
	Date min = d;//早
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int day = 0;
	while (min != max)
	{
		++min;
		++day;
	}
	return  day* flag;
}

计算星期几

void Date::PrintWeekday()
{
	Date start(1900, 1, 1); //查询得星期一
	int count = *this - start;
	cout << "星期" << ((count % 7) + 1) << endl;
}

🌒前置++、–和后置++、–

前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
前置++ 返回 ++ 之后的值
后置++ 返回 ++ 之前的值

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

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

五、代码

Date.cpp

#include "Date.h"
int Date::GetMonthDay(int year, int month)
{
	//静态数组,每次调用不用频繁在栈区创建数组
	static int monthArr[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
	//判断是否闰年
	int day = monthArr[month - 1];
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
	{
		day = 29;
	}
	return day;
}

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


//任何一个类,只需要写一个 > == 重载 或者 < == 即可,剩下比较运算符复用即可
bool Date::operator==(const Date& d)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

// d1 != d2
bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}
//d1 > d2
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)
{
	return (*this == d) || (*this > d);
}
bool Date::operator<(const Date& d)
{
	return !(*this >= d);
}
bool Date::operator<=(const Date& d)
{
	return !(*this > d);
}

// d1 + 100
Date Date::operator+(int day)
{
	Date tmp = (*this);
	tmp += day;

	return tmp;
}

//d2 += d1 += 100   连续加等,有返回值
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;//d1没销毁,可以传引用返回
}


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)
		{
			--_year;
			_month = 12;
		}

		_day += GetMonthDay(_year, _month);
	}
	return *this;
}


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

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

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

//日期-日期
// offerDay - today =>offerDay.operator(&offerday,today);
int Date::operator-(const Date& d)
{
	//假设
	int flag = 1;//防止天数为负
	Date max = *this;//晚
	Date min = d;//早
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int day = 0;
	while (min < max)
	{
		++min;
		++day;
	}
	return  day * flag;
}

void Date::PrintWeekday()
{
	Date start(1900, 1, 1); //查询得星期一
	int count = *this - start;
	cout << "星期" << ((count % 7) + 1) << endl;
}

test.cpp

#include "Date.h"

void test1()
{
	Date d1(2002, 3, 7);
	d1.Print();

	Date d2(2022, 2, 29);
}

//测试+、+=、++
void test2()
{
	Date d1(2022, 1, 16);
	Date ret = d1 + -100;
	ret.Print();

	//Date d2(2022, 1, 16);
	//d2 += 100;
	//d2.Print();

	//++d1;
	/*d1++;*/
}

//测试这一堆运算符重载函数
void test3()
{

	Date d1(2002, 3, 7);
	Date d2(2002, 2, 19); //missing lmyy
	Date d3(2002, 3, 7);

	cout << (d1 == d3) << endl;
	cout << (d1 >= d2) << endl;
	cout << (d1 < d3) << endl;
	cout << (d1 <= d2) << endl;
	cout << (d1 != d3) << endl;

}

// 测试-,-=,--
void test4()
{
	Date d1(2022, 1, 10);
	Date d2(2022, 2, 19);

	Date ret2 = d2 - 60;
	ret2.Print();

	d1 -= 10;
	d1.Print();

	/*--d2;
	d2--;*/
}

//测试日期 - 日期,星期几
void test5()
{
	Date today(2023, 4, 10);
	Date offerDay(2023, 5, 1);
	cout << (offerDay - today) << endl;
	today.PrintWeekday();
}

int main()
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值