C++入门——日期类的实现(内附完整代码)


前言

1日期类的成员变量

class Date
{
public:
	void Print()//这里可以先写一个打印函数,方便我们测试
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;

};

2检查日期合法性函数

//检查日期合法性
bool Date::CheckDate()
{
	if (_month < 1 || _month > 12
		|| _day < 1 || _day > GetMonthDay(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

3获取每年每月的天数

//定义函数用来获取每年每月的天数
	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		static int arr[13][2] = { {-1,-1},{31,31},{28,29},{31,31},
		                        {30,30},{31,31},{30,30},{31,31},
		                        {31,31},{30,30},{31,31},{30,30},{31,31} };
		if ((_year % 4 == 0 && _year % 100 != 0) || _year % 400 == 0)
		{
			return arr[month][1];
		}
		return arr[month][0];
	}

一、默认成员函数

1.1构造函数

//构造函数
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	
	if (!CheckDate())
	{
		cout << "日期非法->";
		cout << *this << endl;
	}
}

1.2析构函数

对于日期类来说,编译器i默认的析构函数就能帮我们解决日期类析构的需求,所以不需要显式写。
析构函数的相关知识,请参考析构函数

1.3拷贝构造函数

对于日期类来说,编译器i默认的拷贝构造函数就能帮我们解决日期类拷贝构造的需求,所以不需要显式写。
拷贝构造函数的相关知识,请参考拷贝构造函数

1.4运算符重载

1.4.1赋值运算符重载

	Date& Date::operator=(const Date& d)
	{
		if (this != &d)//自己拷贝给自己,则直接返回
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

1.4.2比较运算符重载

  • 小于
bool Date::operator<(const Date& d)
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year && _month < d._month)
	{
		return true;
	}
	else if (_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 || *this == d;
}
  • 大于(因为前面我们已经对小于等于进行了重载,所以这里可以直复用
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);
}

1.4.3日期加减天数

  • 加等(+=)
Date& Date::operator+=(int day)
{
	if (day < 0)//如果加的天数是负数,直接调用-=
	{
		return *this -= -day;
	}
	_day = day + _day;
	//加完的天数超出本月天数的上限,进入循环
	while (_day > GetMonthDay(_year, _month))
	{
		_day = _day - GetMonthDay(_year, _month);
		_month = _month % 12;
		if (_month == 0)
		{
			_year++;
		}
		_month++;
	}
	return *this;
}
  • 加(+)
Date Date::operator+(int day)
{
	Date temp = *this;
	temp += day;//复用+=
	return temp;
}
  • 减等
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}
	_day = _day - day;
	while (_day < 1)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day = _day + GetMonthDay(_year, _month);
	}
	return *this;
}
  • 减(-)
Date Date::operator-(int day)
{
	Date temp = *this;
	temp -= day;
	return temp;
}

1.4.4自增和自减

  • 前置++(++d)
Date& Date::operator++()
{
	return *this += 1;
}
  • 后置++(d++)
Date Date::operator++(int)
{
	Date temp = *this;
	*this += 1;
	return temp;
}
  • 前置--(–d)
Date& Date::operator--()
{
	return *this -= 1;
}
  • 后置--(d–)
Date Date::operator--(int) 
{
	Date temp = *this;
	*this -= 1;
	return temp;
}

1.4.5日期 - 日期

对于日期类来说,日期加日期没有意义

//日期-日期
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 count = 0;
	while (min != max)
	{
		min++;
		count++;
	}
	return count * flag;
}

1.4.6<<和>>重载

  • 重载<<和>>时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调⽤时就变成了对象<<cout,不符合使⽤习惯和可读性。如下面的代码所示:
void Date::operator<<(ostream& out)
{
	out << _year << "年" << _month << "月" << _day << "日" << endl;
}

int main()
{
	Date d(2024,10,1);
	//输出打印d,不符合使⽤习惯和可读性
	d<<cout;//正常来说应该是	cout<<d
	return 0;
}

  • 重载为全局函数把ostream/istream放到第⼀个形参位置就可以了,第⼆个形参位置当类类型对象。
    但重载为全局函数时,又会面临一个问题,那就是成员变量是私有的不允许全局访问。那我们再引入友元的概念
    举个例子:你家有一块羽毛球场地,是你私有的别人不能用。但是呢你规定你的朋友可以来使用。所以友元的友也就是朋友的意思。
    友元私有还是公有无所谓。

//>>输出

class Date
{
	//友元函数声明
	friend ostream& operator<<(ostream& out, const Date& d);
public:
	//....
private:
	int _year;
	int _month;
	int _day;

};

//<<(定义为全局函数)
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

<<插入

class Date
{
	//友元函数声明
	friend istream& operator>>(istream& in, Date& d);
	friend ostream& operator<<(ostream& out, const Date& d);
public:
	//....
private:
	int _year;
	int _month;
	int _day;

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

二、完整代码

这里有些函数用const修饰,至于原因,请参考下面的文章:
取地址运算符重载

2.1头文件(Date.h)

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
	//友元函数声明
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	//构造函数
	Date(int year = 2002, int month = 1, int day = 9);

	void Print() const;

	int GetMonthDay(int year, int month) const
	{
		assert(month > 0 && month < 13);
		static int arr[13][2] = { {-1,-1},{31,31},{28,29},{31,31},{30,30},{31,31},{30,30},{31,31},{31,31},{30,30},{31,31},{30,30},{31,31} };
		if ((_year % 4 == 0 && _year % 100 != 0) || _year % 400 == 0)
		{
			return arr[month][1];
		}
		return arr[month][0];
	}
	//检查日期合法性
	bool CheckDate() const;

	Date& operator=(const Date& d);

	bool operator<(const Date& d) const;
	bool operator>(const Date& d) const;
	bool operator<=(const Date& d) const;
	bool operator>=(const Date& d) const;
	bool operator==(const Date& d) const;
	bool operator!=(const Date& d) const;

	Date& operator+=(int day);
	Date operator+(int day) const;

	Date& operator-=(int day);
	Date operator-(int day) const;

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

	Date& operator--();//前置
	Date operator--(int);//后置

	//日期-日期
	int operator-(const Date& d) const;

	//<<
	//void operator<<(ostream& out);
private:
	int _year;
	int _month;
	int _day;

};

//<<
ostream& operator<<(ostream& out, const Date& d);
//>>
istream& operator>>(istream& in, Date& d);


2.2源文件(Date.cpp)

#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"

//构造函数
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	
	if (!CheckDate())
	{
		cout << "日期非法->:";
		cout << *this << endl;
	}
}

//检查日期合法性
bool Date::CheckDate() const
{
	if (_month < 1 || _month > 12
		|| _day < 1 || _day > GetMonthDay(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

Date& Date::operator=(const Date& d)
{
	if (this != &d)//自己拷贝给自己,则直接返回
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}

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

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

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

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

Date& Date::operator+=(int day)
{
	if (day < 0)//如果加的天数是负数,直接调用-=
	{
		return *this -= -day;
	}
	_day = day + _day;
	//加完的天数超出本月天数的上限,进入循环
	while (_day > GetMonthDay(_year, _month))
	{
		_day = _day - GetMonthDay(_year, _month);
		_month = _month % 12;
		if (_month == 0)
		{
			_year++;
		}
		_month++;
	}
	return *this;
}

Date Date::operator+(int day) const
{
	Date temp = *this;
	temp += day;//复用+=

	//temp._day = day + temp._day;
	//while (temp._day > GetMonthDay(temp._year, temp._month))
	//{
	//	temp._day = temp._day - GetMonthDay(temp._year, temp._month);
	//	temp._month = temp._month % 12;
	//	if (temp._month == 0)
	//	{
	//		temp._year++;
	//	}
	//	temp._month++;
	//}
	return temp;
}

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

Date& Date::operator++()
{
	return *this += 1;
}
Date Date::operator++(int)
{
	Date temp = *this;
	*this += 1;
	return temp;
}

Date& Date::operator--()
{
	return *this -= 1;
}
Date Date::operator--(int) 
{
	Date temp = *this;
	*this -= 1;
	return temp;
}

//日期-日期
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;
}

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


2.3测试函数(test.cpp)

这里只是我的一些测试,大家可以对日期类的操作进行各种测试

#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"

int main()
{
	Date d1(2002, 1, 9);
	d1.Print();
	d1 = d1 + 8304;
	d1.Print();
	d1 -= 8000;
	d1.Print();
	(d1++).Print();
	(++d1).Print();

	Date d2(2002, 1, 9);
	Date d3(2024, 10, 4);
	int day = d3 - d2;
	printf("相差%d天\n", day);

	Date d4(2024, 4, 14);
	Date d5 = d4 + 30000;
	// operator<<(cout, d1)
	cout << d4;
	cout << d5;
	cin >> d4 >> d5;
	cout << d4 << d5;

	return 0;
}

2.4测试结果

在这里插入图片描述


总结

以上就是日期类的实现,也算是对前面几节的总结和应用。
今天也是国庆假期,祝我们国庆节快乐,祝祖国母亲繁荣昌盛。祝祖国统一指日可待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值