C++类&对象&运算符重载综合应用——日期类项目的实现

一、引言

类、对象与运算符的重载,是C++的入门基础,同时也是C++的重点模块,是后面面向对象编程、STL等内容的核心,本文将在类、对象、运算符重载的基础上,进一步实现类、对象、运算符重载三者的综合应用,完成一个日期类项目,该项目包括了对日期的加减、日期大小的比较、求两个日期的相差天数等函数的实现,该项目综合应用了类、对象、运算符重载三大板块的内容,应用性很强,适合广大C++学者学习和实现的一个小项目。

目录

一、引言

二、项目实现

1、项目文件

2、日期类成员

(1)成员变量

(2)成员函数

3、函数实现

(1)构造函数

(2)print函数

(3)Getmonthday函数

(4)Checkdate函数

4、运算符重载函数

(1)operator+=重载

(2)operator+重载

(3)operator-=重载

(4)operator-重载

(5)operator<重载

(6)operator==重载

(7)operator<=重载

(8)operator>重载

(9)operator>=重载

(10)operator!=重载

(11)operator++()重载

(12)operator++(int)重载

(13)operator--()重载

(14)operator--(int)重载

(15)求两个日期相差天数(operator-)

(16)operator&重载

(17)operator<<重载

(18)operator>>重载

三、结语

二、项目实现

1、项目文件

(1)

我们将项目的实现分为3个文件,Date.h头文件、Date.cpp实现文件、Test.cpp测试文件。

Date.h头文件主要用于函数的声明、以及部分函数的实现。

Date.cpp实现文件用于实现Date.h头文件中的函数。

Test.cpp测试文件用于测试Date.cpp文件实现的函数。

2、日期类成员

(1)成员变量

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
class Date
{
private:
	int _year;
	int _month;
	int _day;
}

在Date.h头文件中声明日期Date类的成员变量,日期类的成员变量包括年_year、月_month、日_day,在Date类中一般为类私有,为private类型,一般不允许外界访问。

(2)成员函数

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
class Date
{
	//友元函数声明
	friend ostream& operator<<(ostream& out,const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1);
	void print()const;
	bool Checkdate()const;
	//默认是inline
	int Getmonthday(int year, int month)const
	{
		assert(month > 0 && month < 13);
		static int montharray[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  montharray[month];
	}
	Date operator+(int day)const;
	Date& operator+=(int day);
	Date& operator-=(int day);
	Date operator-(int day)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;
	bool operator!=(const Date& d)const;
	//++d
	Date& operator++();
	//d++
	Date operator++(int);
	//--d
	Date& operator--();
	//d--
	Date operator--(int);
	int operator-(const Date& d)const;
	//void operator<<(ostream& out);
	//非常量对象
	Date* operator&()
	{
		//return this;
		return (Date*)0x20250930;
	}
	//常量对象
	const Date* operator&()const
	{
		//return this;
		return (Date*)0x20251001;
	}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

日期类Date的成员函数较多,包括了对日期的加减、日期的大小比较关系、求两个日期的相差天数等等一系列函数,可参考上图Date.h头文件的函数声明,这些成员函数为public类型,允许外界访问,由于函数较多,这里不逐一展开说明,下文实现这些函数时将详细展开介绍。

3、函数实现

(1)构造函数

构造函数声明(Date.h)

Date(int year = 1, int month = 1, int day = 1);

日期构造函数的参数为年year、月month、日day,三个参数我们都设为缺省参数,默认值为1。

构造函数实现(Date.cpp)

#include"Date.h"
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

日期构造函数在Date.h头文件中声明,实现在Date.cpp实现文件中完成,Date.cpp实现文件需包含Date.h头文件的函数声明,日期构造函数与下面要实现的成员函数都类似,日期构造函数为成员函数,在类外实现需指明所在类域Date,函数实现只需将参数year、month、day的值赋值给成员变量_year、_month、_day即可。

(2)print函数

print函数声明(Date.h)

void print()const;

print函数用于打印日期信息,无返回类型,const用于修饰对象,使得对象只读不可写。

print函数实现(Date.cpp)

//void Date::print(const Date*const this);
void Date::print()const
{
	cout << _year << "/" << _month << "/" << _day << endl;
}

print函数实现只需将成员变量_year、_month、_day以_year/_month/_day的日期形式打印出来即可,即cout<<_year<<"/"<<_month<<"/"<<_day<<endl,const用于修饰对象,相当于const Date*const this,使得对象只读不能写。

print函数测试(Test.cpp)

(2)

print函数测试在Test.cpp测试文件中完成,如图(2)所示,先调用构造函数完成d1的初始化,即Date d1(2025,10,1),随后直接调用成员函数print,即d1.print(),屏幕上显示2025/10/1,表明print函数测试成功,同时也表明构造函数Date测试成功。

(3)Getmonthday函数

Getmonthday函数声明和定义(Date.h)

//默认是inline
	int Getmonthday(int year, int month)const
	{
		assert(month > 0 && month < 13);
		static int montharray[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  montharray[month];
	}

Getmonthday用于获取当前月份的天数,Getmonthday与前面函数不同在于Getmonthday函数声明与定义都在Date.h头文件中完成,之所以不分离Getmonthday函数的声明与定义,是因为在类中实现的函数默认为inline内联函数,内联函数会在函数调用处直接展开,不需创建函数栈帧,可以提高函数调用的效率,由于Getmonthday函数在后续函数实现中经常要调用,频繁调用且代码量并不大,因此我们选择在类中实现该函数。

Getmonthday函数参数为年year、月month,返回该月的天数,const修饰对象,只读不可写,assert断言确保月份有效,用一维数组存储每个月份的天数,该数组有13个元素,数组首元素设为-1,后面12个元素依次为1~12月的天数,可知数组下标所对应的元素即为该下标作为月份时的天数,数组用static修饰,存储在静态区,为全局变量,可多次调用,之后考虑2月这一特殊月份,当年份为闰年时,2月有29天,我们采用if进行条件判断,当月份为2且为闰年时,返回29,一般情况下,则返回该月份作为下标时对应的元素,即为该月份的天数。

Getmonthday函数测试(Test.cpp)

(3)

在Test.cpp中测试Getmonthday函数,以d1为测试样例,求d1的月份天数,Getmonthday为d1的成员函数,即d1.Getmonthday(2025,10),ret用来接收d1.Getmonthday(2025,10)的返回值,结果为31,测试结果正确,Getmonthday函数测试通过。

(4)Checkdate函数

Checkdate函数声明(Date.h)

bool Checkdate()const;

Checkdate函数用于判断日期是否合法,返回类型为bool类型,const用于修饰对象,可读不可写。

Checkdate函数实现(Date.cpp)

bool Date::Checkdate()const
{
	if (_month < 1 || _month>12 || _day<1 || _day>Getmonthday(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

Checkdate函数实现即判断月份是否在1~12之间,以及日期是否大于0且不得超过该月的天数,若不符合条件,则返回false,反之则返回true。

Checkdate函数也可加在构造函数中,用来判断构造函数的日期是否非法。

#include"Date.h"
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	if (!Checkdate())
	{
		cout << "非法日期:";
		print();
	}
}

Checkdate函数测试(Test.cpp)

(4)

在Test.cpp文件中对Checkdate函数进行测试,首先构造函数对d1进行初始化,即Date d1(2025,10,32),为非法日期,随后调用d1的成员函数Checkdate进行判断,即d1.Checkdate(),ret接收返回值,结果显示日期为非法日期,ret==0,表明测试结果正确,Checkdate函数测试通过。

4、运算符重载函数

(1)operator+=重载

operator+=重载函数声明(Date.h)

Date& operator+=(int day);

operator+=重载函数用于计算日期加上天数后的日期,函数参数为要加的天数,返回该日期的引用,选择返回值也是可以的,返回引用可以减少拷贝。

operator+=重载函数实现(Date.cpp)

Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > Getmonthday(_year, _month))
	{
		_day -= Getmonthday(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}

operator+=函数实现先对成员变量_day+=day,之后再判断_day是否超过该月的天数,通过Getmonthday函数判断,若超过该月的天数,_day则向_month发生进位,_month++,_day需减掉该月的天数,还需考虑一种特殊情况,当_month==12时,这时_month++,则_month==13,这时_month向_year进位,_year++,_month置为1,while循环结束条件为_day不再大于该月的天数,循环结束,由于+=运算符,故返回this指针所指向的对象,即return *this,选择引用返回,相比传值返回,可以减少拷贝。

operator+=重载函数测试(Test.cpp)

(5)

对operator+=重载函数进行测试,构造函数先初始化d1,即Date d1(2025,10,1),对运算符+=重载后,就可直接使用+=运算符即可,无需使用函数名operator+=来完成调用,即d1+=100,再调用成员函数print()查看最后的结果,结果显示为2026/1/9,经验证后结果正确,operator+=函数测试通过。

(2)operator+重载

operator+重载函数声明(Date.h)

Date operator+(int day)const;

operator+重载函数的参数与operator+=一致,都为要加的天数day,const用于修饰this指针指向的对象,使对象可读不可写,operator+与operator+=不同在于返回对象的不同,operator+=会改变运算对象,而operator+不会改变运算对象,operator+运算的结果会保存在一个局部变量中,最后会返回该局部变量的拷贝,注意这里不能返回引用,因为operator+的结果保存在一个局部变量中,当函数执行结束时,该局部变量也会随之销毁,若返回引用,即返回该局部变量的引用,但该局部变量在函数结束时已被销毁,该引用就为野引用了,因此这里就不能返回引用了,只能传值返回,返回该临时变量的拷贝。

operator+函数实现(Date.cpp)

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

operator+函数实现与operator+=函数实现类似,不同在于operator+函数需先创建一个临时变量tmp,将*this拷贝到tmp中,这是为了确保不改变*this的内容,而operator+=会改变*this的内容,这是operator+与operator+=的一大区别,operator+=函数我们前面已经实现过了,随后对tmp+=day即可,最后传值返回tmp的拷贝,这一过程只改变tmp,*this没有改变。

operator+函数测试(Test.cpp)

(6)

在Test.cpp文件中对operator+函数进行测试,先构造并初始化d1,即d1(2025,10,1),再对d2进行初始化,将d1+10拷贝给d2,最后调用print函数打印d1、d2,d1为2025/10/1,可知d1的内容没有改变,d2为2025/10/11,与d1+10的结果一致,operator+函数测试通过。

(3)operator-=重载

operator-=重载函数声明(Date.h)

Date& operator-=(int day);

operator-=函数声明和实现与前面的operator+=函数类似,函数参数为要减的天数,返回类型也为引用,可以减少拷贝。

operator-=重载函数实现(Date.cpp)

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

operator-=重载函数实现与operator+=函数实现类似,当day>0时,先_day-=day,天数相减,再判断相减后的日期是否小于0,若日期小于0,则需借位,_day向_month借位,_month--,_day加上对应月份的天数,这里也需考虑一种特殊情况,当_month--为0时,这时_month需向_year借位,_year--,_month置为12,while循环结束条件为当_day>0时结束循环,当day小于0时,此时_day-=day,可转化为_day+=(-day),因此当day<0时,直接转化为*this+=(-day)即可,最后返回this指针所指向的对象,即return *this。

operator-=重载函数测试(Test.cpp)

(7)

operator-=重载函数测试,先构造并初始化对象d1,即Date d1(2025,10,11),再对d1-=10,调用成员函数print查看结果,可知d1变为2025/10/1,与d1-=10的结果一致,故operator-=重载函数测试通过。

实现了operator-=重载函数,可以对operator+=优化一下,当day小于0时,operator+=day可转化为operator-=(-day),即*this-=(-day)。

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

(4)operator-重载

operator-重载函数声明(Date.h)

Date operator-(int day)const;

operator-重载函数声明与实现也可类比operator+,operator-函数参数为day,表示要减的天数,const用于修饰对象,使对象可读不可写,这里同样需要注意operator-与operator+一样,也只能传值返回,不能传引用返回。

operator-重载函数实现(Date.cpp)

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

operator-重载函数实现与operator+实现也类似,也是先将this指针所指向的对象拷贝到tmp中,保证*this不被修改,之后利用上面已实现的operator-重载函数,对tmp减去day即可,即tmp-=day,最后返回tmp,return tmp即可。

operator-重载函数测试(Test.cpp)

(8)

operator-重载函数测试:先构造并初始化对象d1,即Date d1(2025,10,11),再将d1-10拷贝到d2中,调用成员函数print查看d1、d2的内容,d1为2025/10/11,d1没有发生改变,d2为2025/10/1,与d1-10的结果一致,operator-重载函数测试通过。

(5)operator<重载

operator<重载函数声明(Date.h)

bool operator<(const Date& d)const;

operator<重载用于判断两个日期的大小关系,函数的返回类型为bool,<为双目运算符,左侧运算对象传给成员函数的第一个函数参数this指针所指向的对象,this指针在函数参数中隐式表示,右侧运算对象传右侧对象的引用,也可传值,传引用可以减少拷贝,const Date& d,该const用于修饰右侧运算对象,只读不能写,bool operator<(const Date& d)const 该const用于修饰this指针指向的对象,也是只读不能写。

operator<重载函数实现(Date.cpp)

bool Date::operator<(const Date& d)const
{
	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;
}

operator<重载函数实现即比较两个日期的大小关系,左侧运算对象为this指针指向的对象,右侧运算对象传该对象的引用,相比传值可以减少拷贝,先比较两个日期的年份,若*this的年份小于d的年份,则*this<d,返回true,另一种情况,当二者年份相等时,继续比较二者的月份,若*this的月份小于d的月份,则*this<d,若二者年月都相等,则继续比较二者的_day,_day小的则日期小。以上情况除外,剩下的情况*this均大于d,不符合<的条件,返回false。

operator<重载函数测试(Test.cpp)

(9)

对operator<重载函数进行测试,先构造并初始化d1、d2,即Date d1(2025,10,11),Date d2(2025,10,1),然后对d1、d2进行比较,ret接收d2<d1的返回值,ret=1,可知结果正确,operator<重载函数测试通过。

(6)operator==重载

operator==重载函数声明(Date.h)

bool operator==(const Date& d)const;

operator==重载函数用于判断两个日期是否相等,声明与operator<类似,返回类型、函数参数与operator<一致,const用于修饰this指针指向的对象,使得对象可读不可写。

operator==重载函数实现(Date.cpp)

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

operator==重载函数实现相比operator<较为简单,判断两个日期是否相等,只需判断两个日期对应的年_year、月_month、日_day是否都相等,若三者都相等,则两个日期相等,反之则不相等。

operator==重载函数测试(Test.cpp)

(10)

operator==重载函数测试:先构造并初始化d1、d2,即Date d1(2025,10,11),Date d2(2025,10,1),ret接收d1==d2的返回值,ret==0,与d1!=d2一致,结果正确,operator==重载函数测试通过。

(7)operator<=重载

operator<=重载函数声明(Date.h)

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

operator<=重载函数声明与operator<的返回类型、函数参数一致,const用于修饰this指针指向的对象,使得对象可读不可写。

operator<=重载函数实现(Date.cpp)

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

有了前面的operator<与operator==重载函数,实现operator<=重载就简单了,只需满足二者当中的一种即可,即*this<d || *this==d,这样就实现了operator<=重载函数。

operator<=重载函数测试(Test.cpp)

(11)

operator<=重载函数测试:构造并初始化d1、d2、d3,即Date d1(2025,10,11),Date d2(2025,10,1),Date d3(2025,10,11),ret1接收d2<=d1的返回值,ret2接收d3<=d1的返回值,ret1、ret2均为1,与d2<=d1、d3<=d1一致,结果正确,operator<=重载函数测试通过。

(8)operator>重载

operator>重载函数声明(Date.h)

bool operator>(const Date& d)const;

operator>重载函数声明与operator<类似,可参考上文operator<重载函数的声明说明,这里就不再赘述了。

operator>重载函数实现(Date.cpp)

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

operator>重载函数实现也可借助前面已实现的operator<=函数,对operator<=取反,即!(*this<=d),就实现了operator>重载函数。

operator>重载函数测试(Test.cpp)

(12)

operator>重载函数测试:先构造并初始化d1、d2,即Date d1(2025,10,11),Date d2(2025,10,1),ret1接收d1>d2的返回值,ret1==1,与d1>d2一致,结果正确,operator>重载函数测试通过。

(9)operator>=重载

operator>=重载函数声明(Date.h)

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

operator>=重载函数声明与operator<函数声明类似,可参考operator<重载函数的函数声明。

operator>=重载函数实现(Date.cpp)

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

operator>=重载函数实现可借助前面实现的operator<重载运算符来进行判断,对operator<取反,即!(*this<d),就实现了operator>=重载函数。

operator>=重载函数测试(Test.cpp)

(13)

对operator>=重载函数进行测试:先构造并初始化d1、d2、d3,即Date d1(2025,10,11),

Date d2(2025,10,1),Date d3(2025,10,11),再将d1>=d2,d1>=d3的返回值传给ret1、ret2,ret1与ret2的值均为1,与d1>=d2、d1>=d3一致,结果正确,operator>=重载函数测试通过。

(10)operator!=重载

operator!=重载函数声明(Date.h)

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

operator!=重载函数声明与operator<函数声明类似,可参考operator<的函数声明。

operator!=重载函数实现(Date.cpp)

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

operator!=重载函数实现也可借助前面已实现的operator==重载运算符来进行判断,对operator==取反,即!(*this==d),就实现了operator!=重载函数。

operator!=重载函数测试(Test.cpp)

(14)

operator!=重载函数测试:先构造并初始化对象d1、d2,即Date d1(2025,10,11),Date d2(2025,10,1),ret1接收d1!=d2的返回值,ret==1,与d1!=d2一致,结果正确,operator!=重载函数测试通过。

(11)operator++()重载

operator++()重载函数声明(Date.h)

//++d
	Date& operator++();

operator++()函数实现前置++运算符的重载,函数选择引用返回,也可以传值返回,传引用返回可以减少拷贝。

operator++()重载函数实现(Date.cpp)

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

operator++()重载函数实现利用前面已实现的重载运算符operator+=,即*this+=1,返回this指针指向的对象,return *this即可。

operator++()重载函数测试(Test.cpp)

(15)

operator++()重载函数测试:先构造并初始化对象d1,即Date d1(2025,10,1),随后将++d1拷贝到对象d2,调用成员函数print查看d1、d2,d2变为2025/10/2,与++d1结果一致,operator++()重载函数测试通过。

(12)operator++(int)重载

operator++(int)重载函数声明(Date.h)

//d++
	Date operator++(int);

operator++(int)重载函数实现后置++运算符的重载,相比前置++(operator++())多了一个int形参,这个int形参没有实际意义,只是为了区别前置++与后置++,函数返回需传值返回,不能引用返回,因为后置++的结果是计算之前的值,因此需要先拿一个局部变量保存计算前的值,然后返回该局部变量,若返回引用,则返回该局部变量的引用,由于局部变量在函数结束时自动销毁,则该引用就变为野引用,所以只能传值返回,返回该局部变量的拷贝。

operator++(int)重载函数实现(Date.cpp)

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

operator++(int)函数实现借助前面实现的operator+=重载运算符,创建一个临时变量tmp,将*this拷贝到tmp中,随后*this+=1,最后返回tmp的拷贝,就实现后置++(operator++(int))重载运算符。

operator++(int)重载函数测试(Test.cpp)

(16)

operator++(int)重载函数测试:构造并初始化对象d1,即Date d1(2025,10,1),再将d1++拷贝到对象d2中,调用成员函数print查看d1、d2,d1变为2025/10/2,d2为2025/10/1,与d1++结果一致,operator++(int)重载函数测试通过。

(13)operator--()重载

operator--()重载函数声明(Date.h)

//--d
	Date& operator--();

operator--()函数声明与operator++()函数声明类似,operator--()实现前置--运算符的重载,可参考operator++()的函数声明。

operator--()重载函数实现(Date.cpp)

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

operator--()重载函数实现借助前面已实现的operator-=重载运算符,对*this-=1,返回this指向的对象,return *this即可。

operator--()重载函数测试(Test.cpp)

(17)

operator--()重载函数测试:构造并初始化对象d1,即Date d1(2025,10,1),再将--d1拷贝到d2,调用成员函数print查看d1、d2,d1、d2都为2025/9/30,与--d1的结果一致,故operator--()重载函数测试通过。

(14)operator--(int)重载

operator--(int)重载函数声明(Date.h)

//d--
	Date operator--(int);

operator--(int)重载函数声明与operator++(int)函数声明类似,operator--(int)实现后置--运算符的重载,可参考operator++(int)的函数声明。

operator--(int)重载函数实现(Date.cpp)

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

operator--(int)函数实现借助前面已实现的operator-=重载运算符,先将*this拷贝到临时变量tmp中,再对*this-=1,最后返回tmp的拷贝,即return tmp。

operator--(int)重载函数测试(Test.cpp)

(18)

operator--(int)重载函数测试:构造并初始化对象d1,即Date d1(2025,10,1),再将d1--拷贝到对象d2中,调用成员函数print查看d1、d2,d1为2025/9/30,d2为2025/10/1,与d1--的结果一致,operator--(int)重载函数测试通过。

(15)求两个日期相差天数(operator-)

函数声明(Date.h)

int operator-(const Date& d)const;

operator-该函数用于求两个日期的相差天数,函数返回值为两个日期相差的天数,第一个运算对象为this指针所指向的对象,第二个运算对象通过传该对象的引用,可以减少拷贝,const Date& d的const用于修饰该对象只读不能写,int operator-(const Date& d)const ,该const用于修饰this指针指向的对象,也是使对象只读不能写。

函数实现(Date.cpp)

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

函数实现中定义了一个符号标志位flag,flag初始化为1,整形变量n初始化为0,采用假设法,先假设*this为较大的日期,随后if语句进行判断,若*this<d,则将d赋值给max,*this赋值给min,这时*this-d小于0,符号位flag置为-1,这样max就是较大的日期,min就是较小的日期,通过while循环计算出两者相差的天数,当min!=max时,min++,n++,直到min==max,此时的n就是两者相差的天数,最后返回n与符号位flag的乘积,就是两个日期相差的天数。

函数测试(Test.cpp)

(19)

对函数进行测试:先构造并初始化对象d1、d2,即Date d1(2025,10,1),Date d2(2025,7,5),ret接收d1-d2的返回值,即二者相差的天数,ret==88,经验证结果正确,函数测试通过。

(16)operator&重载

operator&重载函数一般不需要我们自己来实现,编译器默认会帮我们实现。除非在一些特殊情况,例如我们不想让他人获取成员的地址,这时我们就可以自己实现一个operator&函数,然后胡乱返回一个地址,如下图代码所示:

operator&函数声明和实现(Date.h)

//非常量对象
	Date* operator&()
	{
		//return this;
		return (Date*)0x20250930;
	}
	//常量对象
	const Date* operator&()const
	{
		//return this;
		return (Date*)0x20251001;
	}

两个operator&函数,一个用const修饰的operator&,是用来获取常量对象的地址,不加const修饰的operator&获取非常量对象的地址,正常情况下二者都返回this指针,但如果不想让他人取到地址,则只需胡乱返回一个地址即可。

operator&函数测试(Test.cpp)

(20)

如上图,构造并初始化d1、d2,d2用const修饰,为常量对象,我们对&进行了重载,这时d1、d2的地址就变为了我们自己设置的地址,他人无法得知d1、d2的正确地址,operator&函数测试通过。

(17)operator<<重载

operator<<重载函数声明(Date.h)

ostream& operator<<(ostream& out, const Date& d);
//友元函数声明
	friend ostream& operator<<(ostream& out,const Date& d);

重载<<和>>需要重载为全局函数,因为若重载为成员函数,this指针默认抢占了第一个形参位置,第一个形参位置是左侧运算对象,调用时就变成了对象<<cout,不符合使用习惯和可读性。重载为全局函数,由于<<和>>是ostream和istream的对象,因此把ostream/istream放到第一个形参位置就可以了,第二个形参位置为类类型对象,传引用可以减少拷贝,const修饰对象可读不可写。operator<<重载函数的返回类型为ostream&,方便连续输出,引用返回可以减少拷贝。

这里需要注意的是operator<<重载函数不为成员函数,一般情况下不能访问类中的成员变量_year、_month、_day,需要在类中加上友元函数声明,函数才能访问类中的成员变量,即在函数声明前加上friend关键字,即friend ostream& operator<<(ostream& out,const Date& d)。

operator<<重载函数实现(Date.cpp)

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

operator<<重载函数实现即将日期对象的成员变量_year、_month、_day按年月日的方式依次输出,返回cout的引用,方便连续输出。

operator<<重载函数测试(Test.cpp)

(21)

operator<<重载函数测试:先构造并初始化对象d1、d2,即Date d1(2025,10,1),Date d2(2025,10,2),再对operator<<进行测试,即cout<<d1<<d2<<endl,结果为2025年10月1日、2025年10月2日,结果正确,operator<<重载函数测试通过。

(18)operator>>重载

operator>>重载函数声明(Date.h)

istream& operator>>(istream& in, Date& d);
friend istream& operator>>(istream& in, Date& d);

operator>>重载函数声明与operator<<类似,函数返回类型为istream&,为cin的引用,方便连续输入,将istream类的对象放到第一个形参位置,符合习惯和可读性,第二个形参为类对象的引用,传引用可以减少拷贝,这里需要注意的是operator>>重载函数不为成员函数,因此一般情况下不能访问类对象的成员变量_year、_month、_day,我们需要在类中加上友元函数声明,函数才能访问类中的成员变量,即在函数声明前加上friend关键字,即friend istream& operator>>(istream& in,Date& d);

operator>>重载函数实现(Date.cpp)

istream& operator>>(istream& in, Date& d)
{
	while (1)
	{
		cout << "请依次输入年月日:>";
		in >> d._year >> d._month >> d._day;
		if (!d.Checkdate())
		{
			cout << "输入日期非法";
			d.print();
			cout << "请重新输入!"<<endl;
		}
		else
		{
			break;
		}
	}
	return in;
}

operator>>重载函数实现依次输入年月日,即in>>d._year>>d._month>>d._day,可检查输入的日期是否合法,调用成员函数Checkdate()进行判断,若非法,则需重新输入,while循环继续下一次的输入,若日期合法,则break跳出循环,返回cin的引用,方便连续输入。

operator>>重载函数测试(Test.cpp)

(22)

operator>>重载函数测试:先构造并初始化对象d1,d2,Date d1,d2,再依次输入d1、d2,cin>>d1>>d2,最后输出查看d1、d2内容,即cout<<d1<<d2<<endl,输入d1为2025 10 1,d2为2025 10 2,d1、d2的输出分别为2025年10月1日,2025年10月2日,可知与输入内容一致,operator>>重载函数测试通过。

三、结语

至此,这个日期类项目的全部函数和重载运算符均已全部实现,该日期类项目综合应用了类、对象、运算符重载三大板块的核心内容,综合性较强,涉及面广,通过这个看似简单的日期类项目,可以看出,在C++中,简单的背后往往隐藏着复杂的细节,从各种的运算符重载到流操作的支持,每一步的实现往往都不简单,需要考虑很多细节,我们实现的这个日期类项目,将数据和操作完美地捆绑在一起,通过运算符重载,让日期操作像操作基本数据类型一样直观,C++的学习,就是这样一个不断重构、拓展和深化的过程,这个项目的实现也很好地证明了这一观点。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值