C++类和对象 练习小项目---日期类的实现.

C++类和对象 练习小项目---日期类的实现._第1张图片

个人主页: :✨✨✨初阶牛✨✨✨
推荐专栏1: C语言初阶
推荐专栏2: C语言进阶
个人信条: 知行合一
本篇简介:>:为了更好的理解C++类和对象的知识,我们可以动手实现一下C++的一个简单的日期类,完成相应的函数,更好的帮助我们理解类和对象.
金句分享:
✨无人问津也好,技不如人也罢✨
✨试着冷静下来,做自己该做的事!✨

目录

  • 前言
  • 一、构造函数
    • 1.1 默认构造函数
    • 1.2 拷贝构造函数
  • 二、获取天数
  • 三、运算符重载
    • 3.1 赋值运算符重载
    • 3.2 日期+=天数
    • 3.3 日期+天数
    • 3.4 日期-=天数 和 日期-天数
    • 3.5 日期-日期
    • 3.6 前置++与后置++
    • 3.7 前置--与后置--
    • 3.8 比较运算符

前言

这是我们需要实现的日期类的接口声明,我们需要的是在Date.cpp文件中实现函数的定义.

class Date
{
public:

	// 获取某年某月的天数
	int GetMonthDay(int year, int month);
	//打印日期类函数
	void Print();
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	// 拷贝构造函数
	Date(const Date& d);
	// 赋值运算符重载
	Date& operator=(const Date& d);
	// 析构函数
	~Date();

	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day);
	// 日期-天数
	Date operator-(int day);
	// 日期-=天数
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();


	// >运算符重载
	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);
	// 日期-日期 返回天数
	int operator-(const Date& d);

private:

	int _year;
	int _month;
	int _day;
};

一、构造函数

1.1 默认构造函数

声明:(在Date类中)

//Date.h
	// 全缺省的构造函数
	Date(int year = 2023, int month = 1, int day = 1);

定义:

//Date.cpp
Date::Date(int year , int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	//这里也就体现出了,成员变量前面'_'的好处,方便与参数区分
}

这里需要注意的是,缺省参数应该在声明处给出,定义时不能有缺省参数,在C++入门章节牛牛有提到过原理.

1.2 拷贝构造函数

使用场景:

Date d1(2023, 4, 26);
Date d2(d1);//使用已存在的对象去初始化另一个对象,被称为拷贝构造

定义:

//Date.cpp
// 拷贝构造函数
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

注意使用引用传参.

二、获取天数

放在以前,牛牛实现获取天数的函数可能会用一个很长的Switch case语句,然后返回每一个天数的时间.

如今,牛牛发现,除了闰年时2月是29天以外,其他时候,每个月的时间是不变的,我们可以使用数组将每个月的天数存起来.

int Date::GetMonthDay(int year, int month)
{
	int day[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))//如果是闰年,且是2月
	{
		day[2] = 29;
	}
	return day[month];
}

这里需要注意的是判断条件month == 2要放在前面
((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)放在后面,因为前面的判断条件很好判断,后面的比较复杂,这样可以提高效率.

三、运算符重载

3.1 赋值运算符重载

注意:
参数const Date& d

  1. const一方面保证右操作数不会被修改,即防止函数写反了功能.
    例如:参照错误写法.
    d1=d2,结果是将d2修改成了d1,偷鸡不成蚀把米.

  2. Date&传引用就不会调用拷贝构造函数去传参,减少拷贝,提高效率.

//运算符重载
Date& Date::operator=(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
	return *this;
}
//错误写法
Date& Date::operator=(Date& d)
{
	d._year=_year; 
	d._month=_month;
	d._day=_day;
	return *this;
}

3.2 日期+=天数

C++类和对象 练习小项目---日期类的实现._第2张图片
示例: 2023年7月28日+80天
C++类和对象 练习小项目---日期类的实现._第3张图片

需要注意的是,如果month往后推一位后为13,则应当将month设置为1,并且year++.

代码实现:

// 日期+=天数
Date& Date:: operator+=(int day)
{
	if (day < 0)//不知道使用者会不会调皮传过来负数
	{
		return *this -= -day;//调用"-="的运算符重载
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))//如果超过当月天数
	{
		_day -= GetMonthDay(_year, _month);//通过调用GetMonthDay函数获取当月天数
		_month++;
		if (_month > 12)//月数超过12,则开始下一年
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}

3.3 日期+天数

日期+=天数不同,日期+天数要求该日期本身没有改变,而是返回日期+天数后的日期

此时,我们需要创建一个临时Dateret,将增加的天数ret进行计算,最后返回ret对象.

// 日期+天数

Date Date:: operator+(int day)
{
	if (day < 0)
	{
		return *this -= -day;//调用"-="的运算符重载
	}
	Date ret;//创建临时对象
	ret._day += day;
	while (ret._day > GetMonthDay(_year, _month))//如果超过当月天数
	{
		ret._day -= GetMonthDay(_year, _month);
		ret._month++;
		if (ret._month > 12)
		{
			ret._month = 1;
			ret._year++;
		}
	}
	return ret;
}

3.4 日期-=天数 和 日期-天数

C++类和对象 练习小项目---日期类的实现._第4张图片

示例:2023年7月28日-100天

需要注意的是,重点是+上月的天数,而不是本月的天数.
C++类和对象 练习小项目---日期类的实现._第5张图片

 // 日期-=天数

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

到了这里,我想日期-天数的实现应该比较简单,牛牛就不多介绍了.

// 日期-天数

 Date Date::operator-(int day)
 {
	 if (day < 0)
	 {
		 *this -= day;//调用"-="的运算符重载
	 }
	 Date ret;
	 ret._day -= day;
	 while (ret._day <= 0)//如果是负数
	 {
		 ret._day += GetMonthDay(_year, _month-1);//+上个月的总天数
		 ret._month--;
		 if (ret._month <=0)
		 {
			 ret._month = 12;
			 ret._year--;
		 }
	 }
	 return ret;
 }

3.5 日期-日期

C++类和对象 练习小项目---日期类的实现._第6张图片
日期-日期怎么计算?
例如:
2023年7月28号距离2024年1月1号还有几天?
如果对应的年月日进行想减,然后还需要计算是那些年有那些天,月数又有几天,那可就太麻烦了吧.

所以我们直接先判断两个日期的大小,选择用较小的日期,对齐进行++操作,直到与较大的相等,统计++了多少天,这样是不是就很简单了?
步骤:

  1. 比较日期大小,选出较小者.
  2. 对较小者进行++并统计,直到与较大者相等.
  3. 返回统计的天数.
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	//小的日期一直++,加到和大的日期一样时,加了多少次就差多少天
	Date max = *this;
	Date min = d;
	int flag = 1;
	
	if (*this < d)//如果是左操作数小,则应当是负数
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int n = 0;
	while (min != max)//用n统计相差多少天
	{
		++min;
		++n;
	}
	return n * flag;
}

3.6 前置++与后置++

前置++后置++实现的时候有一个很尴尬的问题,因为前置++和后置++都是单目运算符,即只有一个操作数,那么为了实现他们两个函数能够重载,则只能在后置++处添加一个int类型的参数.
这个参数用户在使用时不需要传递,编译器会自动传递,本质是为了让前置++和后置++进行函数重载.

前置++是返回+1之后的结果,并且this是指向对象本身的,所以我们可以使用传引用返回,减少拷贝,提高效率.

后置++是返回+1之前的值,并且对象最终还需要被修改,所以我们需要创建一个临时对象用于记录+1前对象的日期大小.除此之外,因为临时变量是在局部定义的,所以我们必须传值返回,不能传引用返回.

// 前置++
 Date& Date:: operator++()
{
	 _day +=1;
	 while (_day > GetMonthDay(_year, _month))//如果超过当月天数
	 {
		 _day -= GetMonthDay(_year, _month);//则减去当月的天数
		 //月份向后推一个月
		 _month++;
		 if (_month > 12)
		 {
			 _month = 1;
			 _year++;
		 }
	 }
	 return *this;
}

// 后置++
Date Date::operator++(int)//这个参数为了个与前置++构成函数重载,调用的时候不需要传参.
{
	Date tmp = *this;//要保存++前日期的大小.
	_day += 1;
	while (_day > GetMonthDay(_year, _month))//如果超过当月天数
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month > 12)
		{
			_month = 1;
			_year++;
		}
	}
	return tmp;
}

3.7 前置–与后置–

学了前置++与后置++,这里也是类似的,需要注意的是,+上月的天数.

// 前置--

Date& Date::operator--()
{
	_day -= 1;
	while (_day <= 0)//如果是负数
	{
		_day += GetMonthDay(_year, _month - 1);//+上个月的总天数
		_month--;
		if (_month <= 0)
		{
			_month = 12;
			_year--;
		}
	}
	return *this;
}
// 后置--
Date Date::operator--(int)
{
	Date tmp = *this;
	_day -= 1;
	while (_day <= 0)//如果是负数
	{
		_day += GetMonthDay(_year, _month - 1);//+上个月的总天数
		_month--;
		if (_month <= 0)
		{
			_month = 12;
			_year--;
		}
	}
	return tmp;
}

3.8 比较运算符

比较运算符重载我不多介绍了,没有什么难度.

需要学习的是,可以使用已经实现的>和"=="去复用实现剩下的其他运算符

bool Date::operator>(const Date& d)
{
	if (_year > d._year)//如果年大
	{
		return true;
	}
	{
		if (_year == d._year)
		{
			if (_month > d._month)//年相同,月大
			{
				return true;
			}
			else
			{
				if (_day > d._day)//入如果年月相同,日大
				{
					return true;
				}
				return false;//月小,或者日小和相等
			}
		}
		return false;//如果年小
	}
}

// ==运算符重载

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

// >=运算符重载
bool Date::operator >= (const Date& d)
{
	if (*this > d|| *this == d)
	{
		return true;
	}
	return false;
}

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

日期类就简单实现到这里了,友友们下次见,总代码,可以去我的资源处下载源代码哦.

你可能感兴趣的:(C++,c++,开发语言,c语言,算法)