C++ Date日期类的设计与实现全解析

🔥个人主页:小张同学

🎬作者简介:C++研发方向学习者

📖个人专栏: 《C语言》《数据结构》《C++深度剖析:从入门到深耕》

⭐️人生格言:无视中断,不弃热枕,方得坚持之道。


前言:

前面的文章我们学完了类的基础知识以及一些函数,那么这篇博客就会运用到前面的知识来真正实现一个日期类的各种计算的功能,要把前面的知识结合起来实现Date类。那么带着我们强烈的兴趣一起进入到文章中学习吧~


目录

Date类的主要设计目标:

[一、Date类的 += 与 + 的设计与实现](#一、Date类的 += 与 + 的设计与实现)

1.GetMonthDay函数:

[2. += :](#2. += :)

[3. + :](#3. + :)

4.复用:

[1) + 复用 += :](#1) + 复用 += :)

[2) += 复用 + :](#2) += 复用 + :)

通过对比,得出更好的方法:

5.测试代码test.cpp:

[二、Date类的 -= 与 - 的设计与实现:](#二、Date类的 -= 与 - 的设计与实现:)

[1. -= :](#1. -= :)

[2. - :](#2. - :)

3.测试代码test.cpp:

三、Date类的前置++、--与后置++--的设计与实现:

1.前置++:

2.后置++:

3.前置--:

4.后置--:

5.测试代码test.cpp:

四、Date类的比较运算符的设计与实现:

[1. == :](#1. == :)

[2. > :](#2. > :)

[3. >= :](#3. >= :)

[4. < :](#4. < :)

[5. <= :](#5. <= :)

[6. != :](#6. != :)

7.测试代码test.cpp:

[五、Date类的 日期-日期 的设计与实现:](#五、Date类的 日期-日期 的设计与实现:)

[1. 日期-日期 :](#1. 日期-日期 :)

2.测试代码test.cpp:

六、补充:

1.判断日期是否合法:

2.流插入与流提取:

3.测试代码test.cpp:

七、代码总览:

Date.h

Date.cpp

test.cpp


Date类的主要设计目标:

Date日期类主要的设计目标见下面的Date.h文件:

Date.h

cpp 复制代码
class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month);
 
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
 
	// 拷贝构造函数
    // d2(d1)--this
	Date(const Date& d);
 
	// 赋值运算符重载
    // d2 = d3 -> d2.operator=(&d2, d3)
	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);
 
	//打印
	void Print();
 
private:
	int _year;
	int _month;
	int _day;
};

注意:这里面的打印、析构、拷贝、构造、赋值运算符重载这些函数之前实现过很多次的就不会再写了,大家可以自己去实现一下(当然Date类的析构、拷贝、赋值运算符重载都是可以不写的,使用默认生成的就足够了),最后也可以直接在代码总结里面看 。


一、Date类的 += 与 + 的设计与实现

1.GetMonthDay函数:

因为我们要频繁读取当前的某年某月的天数来实现日期与天数的相关运算,所以我们要先实现一个获取每月天数的函数,也就是GetMonthDay函数,这个我们就直接在类里面定义了,(定义在类里面的成员函数默认为inline),方便我们频繁调用。

cpp 复制代码
// 获取某年某月的天数
int GetMonthDay(int year, int month)
{
	assert(month < 13 && month>0);
	int MonthDayArray[13] = { -1,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;
	}
	return MonthDayArray[month];
}

2. += :

这些函数我们都采用声明与定义分离的方法来写(声明在Date.h,定义在Date.cpp),下面的函数实现都是在Date.cpp中完成的,也就是类域外,所以都要带上类域Date::
设计思路:

因为 += 传给的值也会改变,所以不需要先拷贝一份。我们直接让当前日期的天数加上给的天数,然后进入循环,直到日期合法为止。在循环里每次减掉当月的天数,再++month。当月份达到13时就++year然后把month置为1。就这样,当循环结束时,返回*this(因为this指针出作用域后还存在,可以使用引用返回)

cpp 复制代码
// 日期+=天数
//d1+=100
//方法一:相减法
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		if (_month == 12)
		{
			_day -= GetMonthDay(_year, _month);
			_year += 1;
			_month = 1;
		}
		else {
			_day -= GetMonthDay(_year, _month);
			_month += 1;
		}
	}
	//this出了作用域还在,所以可以用引用返回,减少拷贝
	return *this;
}

方法二:

cpp 复制代码
//方法二:相加法
Date& Date::operator+=(int day)
{
	while (_day+day > GetMonthDay(_year, _month))
	{
		if (_month == 12)
		{
			day -= GetMonthDay(_year, _month) - (_day - 1);
			_day = 1;
			_year += 1;
			_month = 1;
		}
		else {
			day -= GetMonthDay(_year, _month) - (_day - 1);
			_day = 1;
			_month += 1;
		}
	}
	_day += day;
	return *this;
}

3. + :

设计思路:

我们直接令一个对象tmp先把*this拷贝给它,用它去+=就行了,最后返回这个tmp就行(注意tmp出了作用域会销毁,所以不能使用传引用返回)

cpp 复制代码
// 日期+天数
 //采用不复用+=的方法
Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp._day += day;
	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
	{
		if (tmp._month == 12)
		{
			tmp._day -= GetMonthDay(tmp._year, tmp._month);
			tmp._year += 1;
			tmp._month = 1;
		}
		else {
			tmp._day -= GetMonthDay(tmp._year, tmp._month);
			tmp._month += 1;
		}
	}
	return tmp;
}

4.复用:

我们在写完之后会发现上面的代码重复度很高,那我们是不是可以直接复用呢?那是+复用+=好还是+=复用+好呢?下面我们针对这个问题展开讨论:

1) + 复用 += :

cpp 复制代码
// 日期+=天数
//d1+=100
//方法一:相减法
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		if (_month == 12)
		{
			_day -= GetMonthDay(_year, _month);
			_year += 1;
			_month = 1;
		}
		else {
			_day -= GetMonthDay(_year, _month);
			_month += 1;
		}
	}
	//this出了作用域还在,所以可以用引用返回,减少拷贝
	return *this;
}

// 日期+天数
Date Date::operator+(int day)
{
	//这里采用复用+=
	Date tmp(*this);
	tmp += day;
	return tmp;
}

2) += 复用 + :

cpp 复制代码
// 日期+=天数
//用复用+来实现+=
Date& Date::operator+=(int day)
{
	*this = *this + day;
	return *this;
}

// 日期+天数
//采用不复用+=的方法
Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp._day += day;
	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
	{
		if (tmp._month == 12)
		{
			tmp._day -= GetMonthDay(tmp._year, tmp._month);
			tmp._year += 1;
			tmp._month = 1;
		}
		else {
			tmp._day -= GetMonthDay(tmp._year, tmp._month);
			tmp._month += 1;
		}
	}
	return tmp;
}

通过对比,得出更好的方法:

根据图中可知,若用+=复用+,导致拷贝次数增多,原本不用拷贝的+复用+=后要拷贝3次,根据两种方法的拷贝次数,我们可以得出用拷贝多的复用拷贝少的更好,也就是+复用+=。

后续的 - 和 -= 也是一样的道理, - 复用 -= 会更好。

5.测试代码test.cpp:

cpp 复制代码
#include"Date.h"

int main()
{
	Date d1(2025, 8, 1);
	Date d2(d1);
	
	Date ret1 = d1 += 100;
	d1.Print();
	ret1.Print();
	
	Date ret2 = d2 + 100;
	d2.Print();
	ret2.Print();

    return 0;
}


二、Date类的 -= 与 - 的设计与实现:

1. -= :

设计思路:

-=和+=一样,原来的值也会改变,所以不需要额外的对象,然后最后也是直接返回*this就行,可以使用引用返回减少了拷贝。中间的实现思路就是先用当前日期天数减去给的天数,如果<=0就进入循环,先--month(如果为0了就令它变为12之后--year),然后再用天数+=当前月份天数。直到循环结束,返回*this。

cpp 复制代码
// 日期-=天数
//d1-=100
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;
}

2. - :

有了上面的铺垫,这里我们直接采用复用 -= 的方式即可。

cpp 复制代码
// 日期-天数
Date& Date::operator-(int day)
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}

3.测试代码test.cpp:

cpp 复制代码
#include"Date.h"

int main()
{
	Date d3(2025, 8, 1);
	Date d4(d3);

	Date ret3 = d3 -= 100;
	d3.Print();
	ret3.Print();
	
	Date ret4 = d4 - 100;
	d4.Print();
	ret4.Print();

    return 0;
}


三、Date类的前置++、--与后置++--的设计与实现:

下面这些函数我们仍然采用复用的方式,更简洁高效。

1.前置++:

cpp 复制代码
// 前置++
//++d1
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

2.后置++:

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

3.前置--:

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

4.后置--:

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

5.测试代码test.cpp:

cpp 复制代码
#include"Date.h"

int main()
{
    Date d5(2025, 8, 1);
	Date d6(d1);
	Date d7(d1);
	Date d8(d1);

	Date ret5 = ++d5;
	d5.Print();
	ret5.Print();
	
	Date ret6 = d6++;
	d6.Print();
	ret6.Print();
	
	Date ret7 = --d7;
	d7.Print();
	ret7.Print();
	
	Date ret8 = d8--;
	d8.Print();
	ret8.Print();

    return 0;
}


四、Date类的比较运算符的设计与实现:

我们的比较运算符有很多,如:==,>,>=,<,<=,!=。但我们只需要完整的实现其中几个剩下的通过复用和逻辑取反就可以了。

1. == :

cpp 复制代码
// ==运算符重载
bool Date::operator==(const Date& d)
{
	return _year == d._year
        && _month == d._month
        && _day == d._day;
}

2. > :

设计思路:

其实就是先判断年,看谁大,如果相等再判断月份。月份如果能比出来>就直接返回true,不能就继续判断天数,这里直接返回表达式结果就行。最后如果这些判断都不满足了,就返回false 。

cpp 复制代码
// >运算符重载
bool Date::operator>(const Date& d)
{
	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month > d._month)
		{
			return true;
		}
		else if(_month == d._month)
		{
			return _day > d._day;
		}
	}
	return false;
}

3. >= :

这里直接复用 > 和 == 即可,当然也可以不用(见注释掉的部分)。

cpp 复制代码
//// >=运算符重载
//bool Date::operator >= (const Date& d)
//{
//	if (_year < d._year)
//	{
//		return false;
//	}
//	else if (_year == d._year)
//	{
//		if (_month < d._month)
//		{
//			return false;
//		}
//		else if(_month == d._month)
//		{
//			return _day >= d._day;
//		}
//	}
//	return true;
//}
// >=运算符重载
bool Date::operator >= (const Date& d)
{
	return *this > d || *this == d;
}

4. < :

下面的这三个就可以用前面符号的逻辑取反了,比较简单。

cpp 复制代码
// <运算符重载
bool Date::operator < (const Date& d)
{
	return !(*this >= d);

}

5. <= :

cpp 复制代码
// <=运算符重载
bool Date::operator <= (const Date& d)
{
	return !(*this > d);
}

6. != :

cpp 复制代码
// !=运算符重载
bool Date::operator != (const Date& d)
{
	return !(*this == d);
}

7.测试代码test.cpp:

cpp 复制代码
#include"Date.h"

int main()
{
	Date d1(2026, 1, 23);
	Date d2(d1);
	Date d3(2026, 2, 23);
	++d2;
	
	cout << (d2 > d1) << endl;
	cout << (d3 > d1) << endl;
	cout << (d3 > d2) << endl;
	
	cout << (--d2 == d1) << endl;
	cout << (d3 == d1) << endl;
	
	cout << (--d2 >= d1) << endl;
	cout << (++d2 >= d1) << endl;
	cout << (d3 >= d1) << endl;
    //大家可以自己换里面的符号进行测试

    return 0;
}


五、Date类的 日期-日期 的设计与实现:

1. 日期-日期 :

设计思路:

这里有两个思路,但是第二个思路更为巧妙,所以我们采取第二个方法:

先假设*this为较大值,d为较小值。此时的符号就是1(后面直接乘就是正数),但是我们需要进行判断一下,如果假设错了就直接在if语句里改正过来,再令符号标识为-1(后面乘就会为负数)。后续操作就是只要min不等于max就一直--max,n一直++。直到相等,这时的n就是他们两之间相差的天数,然后乘以符号,就是我们想要的结果了。

cpp 复制代码
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	Date max = *this;
	Date min = d;
	int n = 0;
	int falt = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		falt = -1;
	}
	while (max != min)
	{
		--max;
		++n;
	}
	return n * falt;
}

2.测试代码test.cpp:

cpp 复制代码
#include"Date.h"

int main()
{
	Date d1(2026, 1, 23);
	Date d2(d1);
	Date d3(d1);

	Date ret2 = d2 + 100;
	d2.Print();
	ret2.Print();

	int sub1 = ret2 - d2;
	int sub2 = d2 - ret2;

	cout << sub1 << endl;
	cout << sub2 << endl;

    return 0;
}


六、补充:

1.判断日期是否合法:

cpp 复制代码
//判断日期是否合法
bool Date::CheckDate()
{
	if (_month < 1 || _month>12)
	{
		return false;
	}
	if (_day<1 || _day>GetMonthDay(_year, _month))
	{
		return false;
	}
	return true;
}

有了判断日期是否合法这个函数后,可以更新一下全缺省的构造函数以及后面的流提取:

cpp 复制代码
// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	if (!CheckDate())
	{
		cout << "非法日期" << endl;
	}
}

2.流插入与流提取:

重载流插入与流提取:
为了实现连续的流插入与流提取,设置返回类型为ostream&
在成员函数里实现的话this指针会占用左操作数,调用时为d<<cout,不符合习惯,所以在类外实现,cout可占据左操作数,提高可读性。
而重载为全局的函数面临对象访问私有成员变量的问题
有几种方法可以解决:
1、成员放公有
2、Date提供getxxx函数
3、友元函数------这里我们用这个解决!
4、重载为成员函数

使用友元函数,在类中进行友元函数声明即可!

Date.h

cpp 复制代码
#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:
    ......  
};

// 重载流提取与流插入
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);  

Date.cpp

cpp 复制代码
// 重载流插入
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}
cpp 复制代码
// 重载流提取
istream& operator>>(istream& in, Date& d)
{
	while (1)
	{
		cout << "请输入日期(年月日):" << endl;
		in >> d._year >> d._month >> d._day;
		if (d.CheckDate())
		{
			break;
		}
		else
		{
			cout << "非法日期,请重新输入!" << endl;
		}
	}
	return in;
}

3.测试代码test.cpp:

cpp 复制代码
#include"Date.h"

int main()
{
	Date d1(2026, 1, 24);
	Date d2 = d1 + 1000;
	Date d3 = d1;
	Date d4(2026, 13, 12);

	cout << d1 << endl;
	cout << d2 << endl;

	cin >> d2 >> d3;
	cout << d2 << d3 << endl;

    return 0;
}

七、代码总览:

Date.h

cpp 复制代码
#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:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		assert(month < 13 && month>0);
		int MonthDayArray[13] = { -1,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;
		}
		return MonthDayArray[month];
	}

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

	// 拷贝构造函数
	// d2(d1)
	//Date(const Date& d);//使用默认的拷贝构造函数就可以

	//// 赋值运算符重载
	//// d2 = d3 -> d2.operator=(&d2, d3)
	//Date& operator=(const Date& d)//使用默认的赋值运算符重载函数就可以
	//{
	//	if (*this != &d)
	//	{
	//		_year = d._year;
	//		_month = d._month;
	//		_day = d._day;
	//	}
	//	return *this;
	//}

	// 析构函数
	//~Date();//默认的析构函数就可以

	void Print();

	// 日期+=天数
	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);

	// 判断日期是否合法
	bool CheckDate();

	// 流插入
	// 不建议,因为Date* this占据了一个参数位置,使用d<<cout不符合习惯
	//void operator<<(ostream& out);
private:
	int _year;
	int _month;
	int _day;
};

// 重载流提取与流插入
ostream & operator<<(ostream & out, const Date & d);
istream & operator>>(istream & in, Date & d);

Date.cpp

cpp 复制代码
#include"Date.h"


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

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

//// 析构函数
//Date::~Date()
//{
//
//}

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


// 日期+=天数
//d1+=100
//方法一:相减法
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		if (_month == 12)
		{
			_day -= GetMonthDay(_year, _month);
			_year += 1;
			_month = 1;
		}
		else {
			_day -= GetMonthDay(_year, _month);
			_month += 1;
		}
	}
	//this出了作用域还在,所以可以用引用返回,减少拷贝
	return *this;
}

////方法二:相加法
//Date& Date::operator+=(int day)
//{
//	while (_day+day > GetMonthDay(_year, _month))
//	{
//		if (_month == 12)
//		{
//			day -= GetMonthDay(_year, _month) - (_day - 1);
//			_day = 1;
//			_year += 1;
//			_month = 1;
//		}
//		else {
//			day -= GetMonthDay(_year, _month) - (_day - 1);
//			_day = 1;
//			_month += 1;
//		}
//	}
//	_day += day;
//	return *this;
//}

//// 日期+=天数
////用复用+来实现+=
//Date& Date::operator+=(int day)
//{
//	*this = *this + day;
//	return *this;
//}

//// 日期+天数
// //采用不复用+=的方法
//Date Date::operator+(int day)
//{
//	Date tmp(*this);
//	tmp._day += day;
//	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
//	{
//		if (tmp._month == 12)
//		{
//			tmp._day -= GetMonthDay(tmp._year, tmp._month);
//			tmp._year += 1;
//			tmp._month = 1;
//		}
//		else {
//			tmp._day -= GetMonthDay(tmp._year, tmp._month);
//			tmp._month += 1;
//		}
//	}
//	return tmp;
//}

// 日期+天数
Date Date::operator+(int day)
{
	//这里采用复用+=
	Date tmp(*this);
	tmp += day;
	return tmp;
}

//若用+=复用+,导致拷贝次数增多,原本不用拷贝的+复用+=后要拷贝3次
//根据两种方法的拷贝次数,我们可以得出用拷贝多的复用拷贝少的更好,也就是+复用+=


// 日期-=天数
//d1-=100
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-(int day)
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}
 
// 前置++
//++d1
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

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

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

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

// >运算符重载
bool Date::operator>(const Date& d)
{
	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month > d._month)
		{
			return true;
		}
		else if(_month == d._month)
		{
			return _day > d._day;
		}
	}
	return false;
}

// ==运算符重载
bool Date::operator==(const Date& d)
{
	return _year == d._year && _month == d._month && _day == d._day;
}

//// >=运算符重载
//bool Date::operator >= (const Date& d)
//{
//	if (_year < d._year)
//	{
//		return false;
//	}
//	else if (_year == d._year)
//	{
//		if (_month < d._month)
//		{
//			return false;
//		}
//		else if(_month == d._month)
//		{
//			return _day >= d._day;
//		}
//	}
//	return true;
//}
// >=运算符重载
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);
}

// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	Date max = *this;
	Date min = d;
	int n = 0;
	int falt = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		falt = -1;
	}
	while (max > min)
	{
		--max;
		++n;
	}
	return n * falt;
}

//判断日期是否合法
bool Date::CheckDate()
{
	if (_month < 1 || _month>12)
	{
		return false;
	}
	if (_day<1 || _day>GetMonthDay(_year, _month))
	{
		return false;
	}
	return true;
}

// 重载流插入
//为了实现连续的流插入,返回类型为ostream&
//在成员函数里实现的话this指针会占用左操作数,调用时为d<<cout,不符合习惯
//所以在类外实现,cout可占据左操作数,提高可读性
//而重载为全局的面临对象访问私有成员变量的问题
// 有几种方法可以解决:
// 1、成员放公有
// 2、Date提供getxxx函数
// 3、友元函数------这里我们用这个解决!
// 4、重载为成员函数

//先在类中进行友元函数声明
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 << "请输入日期(年月日):" << endl;
		in >> d._year >> d._month >> d._day;
		if (d.CheckDate())
		{
			break;
		}
		else
		{
			cout << "非法日期,请重新输入!" << endl;
		}
	}
	return in;
}

test.cpp

cpp 复制代码
#include"Date.h"

int main()
{
	//Date d1(2025, 8, 1);
	//Date d2(d1);
	//Date d3(d1);
	//Date d4(d1);
	//Date d5(d1);
	//Date d6(d1);
	//Date d7(d1);
	//Date d8(d1);
	//
	////Date ret1 = d1 += 100;
	////d1.Print();
	////ret1.Print();
	////
	////Date ret2 = d2 + 100;
	////d2.Print();
	////ret2.Print();

	////Date ret3 = d3 -= 100;
	////d3.Print();
	////ret3.Print();
	////
	////Date ret4 = d4 - 100;
	////d4.Print();
	////ret4.Print();

	//Date ret5 = ++d5;
	//d5.Print();
	//ret5.Print();
	//
	//Date ret6 = d6++;
	//d6.Print();
	//ret6.Print();
	//
	//Date ret7 = --d7;
	//d7.Print();
	//ret7.Print();
	//
	//Date ret8 = d8--;
	//d8.Print();
	//ret8.Print();

	//Date d1(2026, 1, 23);
	//Date d2(d1);
	//Date d3(2026, 2, 23);
	//++d2;
	//
	//cout << (d2 > d1) << endl;
	//cout << (d3 > d1) << endl;
	//cout << (d3 > d2) << endl;
	//
	//cout << (--d2 == d1) << endl;
	//cout << (d3 == d1) << endl;
	//
	//cout << (--d2 >= d1) << endl;
	//cout << (++d2 >= d1) << endl;
	//cout << (d3 >= d1) << endl;
	
	//Date d1(2026, 1, 23);
	//Date d2(d1);
	//Date d3(d1);
	//Date ret2 = d2 + 100;
	//d2.Print();
	//ret2.Print();
	//int sub1 = ret2 - d2;
	//int sub2 = d2 - ret2;
	//cout << sub1 << endl;
	//cout << sub2 << endl;
	//
	//Date d1(2025, 9, 8);
	//Date d2(d1);
	//Date d3(d1);
	//Date d4(d1);
	//
	//Date ret1 = d1 += 100;
	//d1.Print();
	//ret1.Print();
	//
	//Date ret2 = d2 + 100;
	//d2.Print();
	//ret2.Print();
	//
	//Date ret3 = d3 -= 2000;
	//d3.Print();
	//ret3.Print();
	//
	//Date ret4 = d4 - 2000;
	//d4.Print();
	//ret4.Print();

	Date d1(2026, 1, 24);
	Date d2 = d1 + 1000;
	Date d3 = d1;
	Date d4(2026, 13, 12);

	cout << d1 << endl;
	cout << d2 << endl;

	cin >> d2 >> d3;
	cout << d2 << d3 << endl;

	return 0;
}

本篇博客的完整原代码:

小张同学的CPP仓库------gitee.com


往期回顾:

C++ 类和对象(三):拷贝构造函数与赋值运算符重载之核心实现-CSDN博客

C++ 类和对象(二):实例化、this指针、构造函数、析构函数详解-CSDN博客

C++类和对象(一):inline函数、nullptr、类的定义深度解析-CSDN博客

C++ 入门不迷路:缺省参数、函数重载与引用轻松拿捏-CSDN博客

结语:

这篇博客我们实现了Date类,大家下去之后一定要自己试着完成一下,对后续衔接新的知识很有用,同时也是在复习前面学习的一些知识,其实大家应该可以发现,我们慢慢有了使用场景之后很多问题都清晰很多了,比如传引用返回什么时候可以用,为什么有时候可以用有时候不行,其逻辑是什么,此类问题,随着我们不断的学习,我们最后都会有答案的。如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持。

相关推荐
沉默-_-2 小时前
力扣hot100滑动窗口(C++)
数据结构·c++·学习·算法·滑动窗口
钱彬 (Qian Bin)2 小时前
项目实践19—全球证件智能识别系统(优化检索算法:从MobileNet转EfficientNet)
算法·全球证件识别
feifeigo1232 小时前
基于EM算法的混合Copula MATLAB实现
开发语言·算法·matlab
LYS_06182 小时前
RM赛事C型板九轴IMU解算(4)(卡尔曼滤波)
c语言·开发语言·前端·卡尔曼滤波
while(1){yan}3 小时前
Spring事务
java·数据库·spring boot·后端·java-ee·mybatis
漫随流水3 小时前
leetcode回溯算法(78.子集)
数据结构·算法·leetcode·回溯算法
盛世宏博北京3 小时前
高效环境管控:楼宇机房以太网温湿度精准监测系统方案
开发语言·数据库·php·以太网温湿度变送器
斐夷所非3 小时前
C++ 继承、多态与类型转换 | 函数重载 / 隐藏 / 覆盖实现与基派生类指针转换
c++
毕设源码-赖学姐3 小时前
【开题答辩全过程】以 高校社团管理平台为例,包含答辩的问题和答案
java