【小项目】实现日期计算器(思路讲解+代码实现)

今天我们尝试用C++来实现一下日期计算器,废话少说,发车!


1. 项目认识

https://uutool.cn/date-calc/

这个是网上的日期计算表,我们可以看一下。

2.项目功能

类似于链接中的日期计算机,我们的小项目中也有其功能,我们可以通过天数来找到目标日期,可以计算两个不同日期的相差天数,也可以进行大小比较等。

3.项目实现

3.1****编写思路

对于日期表的创建,首先是要有日期的输入输出方法,然后创建不同的算法函数来实现有意义的日期计算,对于输入,输出,我们也要有合理性的判断,防止不切实际的现象发生。

3.2****步骤预览

  1. 创建头文件&源文件
  2. 初定义日期
  3. 算法实现
  4. 运行检查

3.3****代码实现

1.初定义日期

复制代码
头文件:
// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);

源文件:
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;

	//if(this->CheckDate())
	if (!CheckDate())
	{
		cout << "非法日期->" << *this << endl;
	}
}

2.算法头文件预览

3.计算月份(GetMonthDay)

月份计算是通用功能,写在头文件里是为了:复用、统一、防错、规范。

思路:我们在写的时候,首先考虑到月份的特殊性,比如大小月,闰年的情况;对于大小月,我们可以直接利用数组来具体选择;对于闰年,"四年一闰,百年不闰,四百年再闰",我们在代码书写时,要注意其中的逻辑关系,这是()的使用就很关键。

复制代码
int GetMonthDay(int year, int month)
{
	assert(month > 0 && month < 13);
	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];
}

4.输出打印(Print)

复制代码
void Date::Print() const
{
	cout << _year << "/"<<_month <<"/" << _day << endl;
}

5.异常检查(CheckDate)

注意日期是否符合实际

复制代码
bool Date::CheckDate()
{
	if (_day<1 || _day>GetMonthDay(_year, _month) || _month < 1 || _month>12 )
	{
		return false;
	}
	else
		return true;
}

6."+="的实现

思路:当我们在加天数时,会存在多种情况,比如月份的跨越,年份的跨越,此外也会出现用户输出错误的问题,比如负数。

注意这里使用引用返回可以减少拷贝,提高效率。我们注意下后面使用引用的情况。

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

7."+"的实现

这里没有用引用返回,为什么呢?因为会出现野引用,我们要返回tmp的临时对象,tmp已经销毁。此外我们在return值时,也会犯下错误。

复制代码
Date Date::operator+(int day)
{
	Date tmp = *this;
	tmp += day;
	return tmp ;
}

8."-="的实现

思路:与"+="的情况相反,逻辑相同。

复制代码
Date& Date::operator-=(int day)
{
	if (day < 0)
		return *this += -day;
	_day -= day;
	while (_day <= 0)
	{
		_month = _month - 1;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

9."-"的实现

复制代码
Date Date::operator-(int day)
{
	Date tmp = *this;
	tmp -= day;
	return tmp;

10.前置"++"的实现

复制代码
Date& Date::operator++()
{
	*this+=1;
	return *this;
}

11.后置"++"的实现

复制代码
Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}

这里详细介绍引用返回和传值返回的区别。

12.前置"--"的实现

复制代码
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

13.后置"--"的实现

复制代码
Date Date::operator--(int)
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}

14."=="的实现

复制代码
bool Date::operator==(const Date& d) const
{
	return _year == d._year && _day == d._day && _month == d._month;
}

15."!="的实现

复制代码
bool Date::operator!=(const Date& d) const
{
	return !(*this == d);

16."<"的实现

复制代码
bool Date::operator<(const Date& d) const
{
	if (_year < d._year)
		return true;
	if (_month < d._month)
		return true;
	if (_day < d._day)
		return true;
	return false;
}

17."<="的实现

复制代码
bool Date::operator<=(const Date& d) const
{
	return (*this == d || *this < d);
}

18.">"的实现

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

19.">="的实现

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

20."-"的实现

思路:与"+"的情况相反,但逻辑上更加复杂,不光要注意月份与年份的跨越问题,我们更要判断日期相减的大小情况,这里我们便使用到flag来定义两种情况,来判断运算的正负结果。

复制代码
int Date::operator-(const Date& d) const
{
	Date max = *this;
	Date min = d;
	int flag = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int count = 0;
	while (min != max)
	{
		++min;
		++count;
	}
	return count * flag;
}

21.输入输出的实现(友元函数介绍)

友元函数****是定义在类外部,但有权访问该类的 private /protected 成员的特殊函数。它不是类的成员函数,但被类 "授权" 了访问权限。

首先这里我们要明白为什么要使用友元函数?为什么不把函数包含在类中?这里在上一篇博客中我们详细介绍了,大家可以去看下https://blog.csdn.net/2602_95649725/article/details/160417849?fromshare=blogdetail&sharetype=blogdetail&sharerId=160417849&sharerefer=PC&sharesource=2602_95649725&sharefrom=from_linkhttps://blog.csdn.net/2602_95649725/article/details/160417849?fromshare=blogdetail&sharetype=blogdetail&sharerId=160417849&sharerefer=PC&sharesource=2602_95649725&sharefrom=from_link

复制代码
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);

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

	return out;
}

istream& operator>>(istream& in, Date& d)
{
	while (1)
	{
		cout << "请依次输入年月日:>";
		in >> d._year >> d._month >> d._day;

		if (d.CheckDate())
		{
			break;
		}
		else
		{
			cout << "非法日期,请重新输入!" << endl;
		}
	}

	return in;
}

4.实例输出

5.gitee源码

https://gitee.com/wxx547803_0/ccccc/blob/abda9b34148615b106b96e4b36f53c39fb135bc1/%E4%BB%A3%E7%A0%81/%E6%97%A5%E6%9C%9F%E8%AE%A1%E7%AE%97%E8%A1%A8/%E6%97%A5%E6%9C%9F%E8%AE%A1%E7%AE%97%E8%A1%A8/Date.cpphttps://gitee.com/wxx547803_0/ccccc/blob/abda9b34148615b106b96e4b36f53c39fb135bc1/%E4%BB%A3%E7%A0%81/%E6%97%A5%E6%9C%9F%E8%AE%A1%E7%AE%97%E8%A1%A8/%E6%97%A5%E6%9C%9F%E8%AE%A1%E7%AE%97%E8%A1%A8/Date.cpp

相关推荐
代码中介商2 小时前
C语言进程管理与内存管理深度解析
c语言·开发语言
十五年专注C++开发2 小时前
C++中TAS和CAS实现自旋锁
c++·cas·原子操作·tas
噜噜噜噜鲁先森2 小时前
STL——String类
开发语言·c++·算法
沐知全栈开发2 小时前
Bootstrap 下拉菜单
开发语言
谭欣辰2 小时前
详细讲解 C++ 有向无环图(DAG)及拓扑排序
c++·算法·图论
XS0301062 小时前
Java 基础(七)多态
java·开发语言
不知名的老吴2 小时前
一文读懂:单例模式的经典案例分析
java·开发语言·单例模式
欧米欧2 小时前
C++算法之双指针算法
开发语言·c++
承渊政道2 小时前
【递归、搜索与回溯算法】(掌握记忆化搜索的核心套路)
数据结构·c++·算法·leetcode·macos·动态规划·宽度优先
REDcker2 小时前
跨平台编译详解 工具链配置与工程化实践
linux·c++·windows·macos·c·跨平台·编译