日期类的实现(C++)

 个人主页:Jason_from_China-CSDN博客

所属栏目:C++系统性学习_Jason_from_China的博客-CSDN博客

所属栏目:C++知识点的补充_Jason_from_China的博客-CSDN博客

前言

日期类是六个成员函数学习的总结和拓展,是实践的体现

创建文件

构造函数

//.h文件
#pragma once
#include<iostream>//流文件
#include<assert.h>//断言头文件
using namespace std;//域展开

class Date
{

public:
	//构造函数
	Date(int year = 1901, int month = 1, int day = 1);
    //打印函数
	void print();
private:
	int _year;
	int _month;
	int _day;
};


//.cpp文件
#include"Date.h"
//构造函数
Date::Date(int year, int month, int day)
	:_year(year)
	, _month(month)
	, _day(day)
{}
//打印函数
void Date::print()
{
	cout << _year << "/" << _month << "/" << _day << endl << endl;
}


//测试文件
#include"Date.h"
int main()
{
	//日期类构造函数的测试
	Date d1(111,1,1);
	d1.print();

	return 0;
} 

这里顺手实现一个打印函数, 方便调试,测试一下没有问题

析构函数

日期类是不需要手动实现析构函数的,因为这里是没有开辟的动态空间,默认生成的析构函数已经完全够用

拷贝构造

//拷贝构造函数
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
  • 实现逻辑:
    • _year = d._year;:将传入对象d的年份赋值给新创建对象的年份成员变量。
    • _month = d._month;:将传入对象d的月份赋值给新创建对象的月份成员变量。
    • _day = d._day;:将传入对象d的日期赋值给新创建对象的日期成员变量。
 

通过这三个赋值操作,新创建的Date对象的成员变量被初始化为与传入对象完全相同的值,从而实现了对象的拷贝

运算符重载比较日期的综合实现

等于的实现(==)

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

实现逻辑

 
  1. 首先比较两个对象的年份_year是否相等,如果不相等则直接返回false,表示两个日期不同。
  2. 如果年份相等,接着比较月份_month是否相等。如果不相等,同样返回false
  3. 如果年份和月份都相等,最后比较日期_day是否相等。如果不相等,返回false
  4. 如果年份、月份和日期都相等,那么返回true,表示两个日期对象相等。

小于的实现(<)

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

实现逻辑

  1. 首先比较两个日期对象的年份。如果当前对象的年份_year小于传入对象的年份d._year,说明当前对象的日期更早,直接返回true
  2. 如果年份相等,接着比较月份。如果当前对象的月份_month小于传入对象的月份d._month,说明当前对象的日期仍然更早,返回true
  3. 如果年份和月份都相等,最后比较日期。如果当前对象的日期_day小于传入对象的日期d._day,说明当前对象的日期更早,返回true
  4. 如果以上三个条件都不满足,即年份、月份和日期都不小于传入对象相应的值,说明当前对象的日期不早于传入对象的日期,返回false

小于等于实现(<=)

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

实现逻辑

  1. return *this < d || *this == d;这行代码使用了逻辑或(||)运算符来判断当前对象是否小于等于传入的对象。
    • *this < d表示调用已经重载的小于运算符<,判断当前对象是否小于传入的对象。如果这个条件为真,那么当前对象肯定小于等于传入的对象,直接返回true
    • *this == d表示调用已经重载的等于运算符==,判断当前对象是否等于传入的对象。如果当前对象不小于传入的对象(即*this < d为假),但两个对象相等,那么当前对象也小于等于传入的对象,同样返回true
    • 如果以上两个条件都不满足,即当前对象既不小于传入的对象也不等于传入的对象,那么返回false,表示当前对象大于传入的对象,不满足小于等于的条件。

大于的实现(>) 

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

实现逻辑

  1. return!(*this <= d);这行代码利用了逻辑非(!)运算符和已经实现的小于等于运算符<=来判断当前对象是否大于传入的对象。
    • *this <= d会调用已经重载的小于等于运算符,判断当前对象是否小于等于传入的对象。如果这个条件为真,说明当前对象不大于传入的对象。
    • *this <= d取逻辑非,即!(*this <= d)。如果*this <= d为假,那么逻辑非的结果为真,这就表示当前对象大于传入的对象,直接返回true;如果*this <= d为真,那么逻辑非的结果为假,这就表示当前对象不大于传入的对象,返回false

 大于等于的实现(>=)

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

实现逻辑

  1. return!(*this < d);这行代码利用了逻辑非(!)运算符和已经实现的小于运算符<来判断当前对象是否大于等于传入的对象。
    • *this < d会调用已经重载的小于运算符,判断当前对象是否小于传入的对象。如果这个条件为真,说明当前对象小于传入的对象,那么当前对象就不大于等于传入的对象。
    • *this < d取逻辑非,即!(*this < d)。如果*this < d为假,那么逻辑非的结果为真,这就表示当前对象不小于传入的对象,也就是大于等于传入的对象,直接返回true;如果*this < d为真,那么逻辑非的结果为假,这就表示当前对象小于传入的对象,不满足大于等于的条件,返回false

代码实现

//.h文件
#pragma once
#include<iostream>//流文件
#include<assert.h>//断言头文件
using namespace std;//域展开

class Date
{

public:
	//构造函数
	Date(int year = 1901, int month = 1, int day = 1);
    //打印函数
	void print();

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

private:
	int _year;
	int _month;
	int _day;
};


//.cpp实现文件
#include"Date.h"
//构造函数
Date::Date(int year, int month, int day)
	:_year(year)
	, _month(month)
	, _day(day)
{}
//打印函数
void Date::print()
{
	cout << _year << "/" << _month << "/" << _day << endl << endl;
}

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



//测试文件
#include"Date.h"
int main()
{
	//日期类构造函数的测试
	Date d1(111,1,1);
	d1.print();

	//日期类拷贝构造函数的测试
	Date d2(d1);
	d2.print();

	//日期类获取每个月天数的测试
	int ret1 = d2.GetmonthDay(1999, 2);
	cout << ret1 << endl << endl;

	//比较测试(没有问题)
	Date d3(1, 1, 1);
	Date d4(1, 1, 1);
	Date d5(2, 2, 2);
	bool ret = d3.operator==(d4);
	bool ret2 = d3.operator<(d5);
	bool ret3 = d3.operator<=(d4);
	bool ret4 = d5.operator<=(d3);
	bool ret5 = d5.operator<(d3);
	cout << ret << endl << endl;
	cout << ret2 << endl << endl;
	cout << ret3 << endl << endl;
	cout << ret4 << endl << endl;
	cout << ret5 << endl << endl;
	return 0;
} 

测试:没有问题

获取某一年的某一月份的天数(为日期的加减做下铺垫)

我们进行计算的时候是需要找到某一年的某一月份的天数,然后才能进行加减

这里我们直接写成内联函数,在类里面实现,因为每次计算都需要进行计算时间,我们直接重载为成员函数,这样空间就是开辟好的,节约时间,这也是C++比其他语言迅速的原因,不仅仅是实现上面,还有平时书写习惯上面

  • 这里一个关键点就是getmonthday没有做定义和声明的分离,因为这里超频繁的调用,所以我们定义为内联,频繁的调用定义为内联提高效率
  • 这里返回的是月份的天数
  • 这里判断的时候,有一个小细节,就是先判断月份,因为先判断月份比较简单,后判断年份,这样会稍微提高速度
//这里是放到类里面的	
//获取一个日期(内联函数)
	int GetmonthDay(int year, int month)const
	{
		assert(month < 13 && month>0);
		static 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;
		}
		else
		{
			return monthDayArray[month];
		}
	}

如果是闰年就单独判断一下,四年一润,百年不润,四百年润一次,并且同时月份是二月(每四年会多一天,365天多五小时+),对逻辑进行修改(因为是不是二月比计算更容易判断)

运算符重载+=,+和-=,-的实现

+=的实现

//计算加法
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= day;
	}
	_day += day;
	while (_day > GetmonthDay(_year, _month))
	{
		_day -= GetmonthDay(_year, _month);
		_month += 1;
		if (_month > 12)
		{
			_year += 1;
			_month = 1;
		}
	}
	return *this;
}

实现逻辑

  1. 首先判断传入的天数day是否小于 0,如果是,则调用减法赋值运算符(-=)来处理负数的情况,实现了一种统一的处理方式,避免了重复编写类似的代码。
  2. 如果day大于等于 0,则将其加到当前日期对象的天数_day上。
  3. 然后进入一个循环,检查当前日期的天数_day是否大于当前年份和月份对应的天数(通过调用GetmonthDay(_year, _month)获取)。
    • 如果是,说明当前日期已经超出了当月的天数范围。此时,将当前日期的天数减去当月的天数,即_day -= GetmonthDay(_year, _month),然后月份_month加 1。
    • 如果月份_month超过了 12,说明已经到了下一年,此时将年份_year加 1,并将月份重置为 1。
  4. 循环继续检查新的日期是否仍然超出当月的天数范围,直到日期合法为止。
  5. 最后,返回当前日期对象的引用,以便支持连续的加法赋值操作。

+的实现(复用+=)

Date Date::operator+(int day)const
{
	Date tmp = *this;
	tmp += day;//这里需要注意一个点,不能是this的复用,this的复用会导致自身变化
	return tmp;
}

实现逻辑

  1. Date tmp = *this;:创建一个临时的Date对象tmp,并使用当前对象(*this)进行初始化。这样就复制了当前对象的状态到tmp中。
  2. tmp += day;:调用已经重载的加法赋值运算符+=,在临时对象tmp上加上指定的天数day。这个操作会修改tmp的日期,但不会影响原来的对象(因为tmp是一个对象)。
  3. return tmp;:返回修改后的临时对象tmp,作为加上指定天数后的新日期对象。

-=的实现

//日期类的实现-=
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += day;
	}
	_day -= day;
	while (_day <= 0)
	{
		_month -= 1;
		if (_month == 0)
		{
			_year -= 1;
			_month = 12;
		}
		_day += GetmonthDay(_year, _month);
	}
	return *this;
}

实现逻辑

  1. 首先判断传入的天数day是否小于 0,如果是,则调用加法赋值运算符(+=)来处理负数的情况,实现了一种统一的处理方式,避免了重复编写类似的代码。
  2. 如果day大于等于 0,则将其从当前日期对象的天数_day中减去。
  3. 然后进入一个循环,检查当前日期的天数_day是否小于等于 0。
    • 如果是,说明当前日期已经超出了合法范围,需要进行调整。首先将月份_month减 1。
    • 如果月份_month减到 0,说明已经到了上一年,此时将年份_year减 1,并将月份重置为 12。
    • 接着,将减去的天数加上当前调整后的年份和月份对应的天数(通过调用GetmonthDay(_year, _month)获取),以确保日期的合法性。
  4. 循环继续检查新的日期是否仍然小于等于 0,直到日期合法为止。
  5. 最后,返回当前日期对象的引用,以便支持连续的减法赋值操作。

 -的实现(复用-=)

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

实现逻辑

  1. Date tmp = *this;:创建一个临时的Date对象tmp,并使用当前对象(*this)进行初始化。这样就复制了当前对象的状态到tmp中。
  2. tmp -= day;:调用已经重载的减法赋值运算符-=,在临时对象tmp上减去指定的天数day。这个操作会修改tmp的日期,但不会影响原来的对象(因为tmp是一个副本)。
  3. return tmp;:返回修改后的临时对象tmp,作为减去指定天数后的新日期对象。

代码实现

//.h文件
#pragma once
#include<iostream>//流文件
#include<assert.h>//断言头文件
using namespace std;//域展开

class Date
{

public:
	//构造函数
	Date(int year = 1901, int month = 1, int day = 1);
    //打印函数
	void print();

    //运算符重载
	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;
private:
	int _year;
	int _month;
	int _day;
};







//.cpp实现文件
#include"Date.h"
//构造函数
Date::Date(int year, int month, int day)
	:_year(year)
	, _month(month)
	, _day(day)
{}
//打印函数
void Date::print()
{
	cout << _year << "/" << _month << "/" << _day << endl << endl;
}

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

//计算加法
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= day;
	}
	_day += day;
	while (_day > GetmonthDay(_year, _month))
	{
		_day -= GetmonthDay(_year, _month);
		_month += 1;
		if (_month > 12)
		{
			_year += 1;
			_month = 1;
		}
	}
	return *this;
}
Date Date::operator+(int day)const
{
	Date tmp = *this;
	tmp += day;//这里需要注意一个点,不能是this的复用,this的复用会导致自身变化
	return tmp;
}
//日期类的实现-=
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += day;
	}
	_day -= day;
	while (_day <= 0)
	{
		_month -= 1;
		if (_month == 0)
		{
			_year -= 1;
			_month = 12;
		}
		_day += GetmonthDay(_year, _month);
	}
	return *this;
}
Date Date::operator-(int day)const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}





//测试文件
#include"Date.h"
int main()
{
	//日期类构造函数的测试
	Date d1(111,1,1);
	d1.print();

	//日期类拷贝构造函数的测试
	Date d2(d1);
	d2.print();

	//日期类获取每个月天数的测试
	int ret1 = d2.GetmonthDay(1999, 2);
	cout << ret1 << endl << endl;

	//比较测试(没有问题)
	Date d3(1, 1, 1);
	Date d4(1, 1, 1);
	Date d5(2, 2, 2);
	bool ret = d3.operator==(d4);
	bool ret2 = d3.operator<(d5);
	bool ret3 = d3.operator<=(d4);
	bool ret4 = d5.operator<=(d3);
	bool ret5 = d5.operator<(d3);
	cout << ret << endl << endl;
	cout << ret2 << endl << endl;
	cout << ret3 << endl << endl;
	cout << ret4 << endl << endl;
	cout << ret5 << endl << endl;

	//测试日期类的加等和加
	Date d6;
	d6 += 1000;
	d6.print();
	Date ret6 = d6 + 10000;
	ret6.print();
	
	//测试日期类的减等和减
	Date d7;
	d7 -= 10000;
	d7.print();
	Date d8;
	Date ret8 = d8 - 1000;
	ret8.print();
	return 0;
} 

测试:没有问题

 

为什么有一个判断是否是负值的判断:

这里提醒一下,规范(+,+=,-,-=)的格式,防止因为传参传递的是负数从而导致计算出现误差,简单的说当是+=的时候传递的数值是负值,我们直接去调用-=

运算符重载++和--的实现

前置和后置的区别

我们以++来说明 

一般我们会给后置类型加上一个参数

也就是:

当然这里你也可以传递0或者1

前置++

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

实现逻辑

 
  1. return *this += 1;这行代码通过调用已经重载的加法赋值运算符+=来实现日期的自增。这里将整数 1 作为参数传递给+=运算符,表示将日期增加一天。
  2. *this表示当前的日期对象,通过调用+=运算符,在当前日期对象上加上一天。这个操作会修改当前对象的日期状态。
  3. 最后,返回当前日期对象的引用,以便支持连续的自增操作。

后置++

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

实现逻辑

 
  1. Date tmp = *this;:创建一个临时的Date对象tmp,并使用当前对象(*this)进行初始化。这样就复制了当前对象的状态到tmp中,保存了自增前的日期对象。
  2. *this += 1;:调用已经重载的加法赋值运算符+=,在当前对象上加上一天,实现日期的自增操作。
  3. return tmp;:返回临时对象tmp,即自增前的日期对象副本。这里的关键在于对象本身进行+,但是返回的是创建的临时对象

前置--

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

实现逻辑

 
  1. return *this -= 1;这行代码通过调用已经重载的减法赋值运算符-=来实现日期的自减。这里将整数 1 作为参数传递给-=运算符,表示将日期减少一天。
  2. *this表示当前的日期对象,通过调用-=运算符,在当前日期对象上减去一天。这个操作会修改当前对象的日期状态。
  3. 最后,返回当前日期对象的引用,以便支持连续的自减操作。

后置--

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

实现逻辑

 
  1. Date tmp = *this;:创建一个临时的Date对象tmp,并使用当前对象(*this)进行初始化。这样就复制了当前对象的状态到tmp中,保存了自减前的日期对象。
  2. *this -= 1;:调用已经重载的减法赋值运算符-=,在当前对象上减去一天,实现日期的自减操作。
  3. return tmp;:返回临时对象tmp,即自减前的日期对象副本。

 计算日期之间相差多少天

这里有坑,这里有坑,这里有坑

首选我们直接上代码,因为代码是很简单的,但是有一些语法结构是有坑的

//日期之间相差多少天
int Date::operator-(const Date& d)const
{
	//这里采取假设法,假设this是大的,如果不是,则进行转换
	Date max = *this;
	Date min = d;
	int flag = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int cout = 0;
	while (max != min)
	{
		++min;
		++cout;
	}
	return cout* flag;
}

//测试
int main()
{
    Date ret6 = d6 + 10000;
    ret6.print();
    //首先,编译器尝试寻找一个可以处理d6 + 10000的操作符重载函数,比如operator + (int),
    //如果没有找到这样的函数。
    //然后,编译器可能会尝试将d6 + 10000解释为d6.operator+(Date(10000)),
    //也就是先通过单参数构造函数将整数10000转换为一个临时的Date对象,
    //然后再尝试调用可能存在的operator + (const Date&)成员函数来执行加法操作。
    //
    // 两个解决办法
    // 1, explicit Date(int value);
    //使用explicit关键字后,编译器将不会自动使用这个单参数构造函数进行隐式类型转换,从而避免了意    外的行为。
    // 2,加上const修饰
 

	//测试日期类的减等和减
	Date d7;
	d7 -= 10000;
	d7.print();
	Date d8(2000,1,1);
	Date ret8 = d8 - 1000; //原因是:1000但参构造成为了Date对象,导致调用不明确 禁止掉可以解决折扣的问题
	ret8.print(); //如果你给那个函数加上了const就只有const对象可以调用  不会出现调用不明确了

    RETURN 0;
}

逻辑注意:

  1. 首先我们实现逻辑的时候,不能真的这个用日期和日期直接相互减减,因为那样会很麻烦
  2. 所以我们可以直接利用追击问题,当数值一样的时候,我们就可以跳出循环

实现逻辑

  1. 首先进行大小判断和初始化:
    • Date max = *this;Date min = d;以及int flag = 1;这几行代码假设当前对象(*this)是较大的日期,将其赋值给max,传入的参数对象d赋值给min,并设置标志变量flag为 1。
    • 如果当前对象实际上小于传入的对象,即*this < d,则进行交换:max = d;min = *this;,同时将标志变量flag设为 -1。这样确保max始终是较大的日期,min始终是较小的日期。
  2. 然后计算日期差:
    • 使用一个循环while (max!= min),只要两个日期不相等就继续循环。
    • 在循环中,每次将较小的日期min递增一天(这里假设Date类实现了自增运算符++,使其能够正确地增加一天,同时处理月份和年份的变化),并将天数计数器cout加一。
    • 当两个日期相等时,循环结束。
  3. 最后返回结果:
    • 将天数计数器cout乘以标志变量flag,得到最终的日期差。如果一开始假设正确,即当前对象较大,那么返回正数的日期差;如果当前对象较小,返回负数的日期差。

这里有坑的点:

所以还是回到那一句话,const应加尽加

 C++流插入(输出到屏幕上面)和流提取(输入)

方式1:重载为成员函数

这里解释一下,重载为成员函数是可以的,但是是不符合我们的使用习惯,我这里用图解解释一下,了解就可以,逻辑思路都一样

 方式2(使用):友元函数

这里是比较多的使用方式,友元函数也是比较简单的,只需要再函数的公有区域加上

friend+函数全称;

流插入(输出)(重载为全局函数):

//流插入(输出到屏幕)//给返回值,支持连续赋值,不然只能一次打印一个
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl << endl;
	return out;
}

注意

  1. 这里的out是cout的简称
  2. 这里我们需要有返回值的目的是,支持链式操作,也就是输入可以连续输入,输出可以连续输出,没有返回值只能实现单次
  3. 有返回值能实现链式操作,因为对于赋值运算而言赋值是从右往左实现的,但是对于插入流而言是从左往右实现的 ,每次都会返回cout从而进行下一次的操作

实现逻辑

 
  1. out << d._year << "年" << d._month << "月" << d._day << "日" << endl << endl;这行代码将日期对象d的年份、月份和日期按照特定格式输出到输出流out中。
    • 首先输出年份d._year,并紧跟一个 “年” 字。
    • 接着输出月份d._month,并紧跟一个 “月” 字。
    • 然后输出日期d._day,并紧跟一个 “日” 字。
    • 最后输出两个换行符endl << endl,用于在输出日期后进行换行,使输出更加清晰。
  2. return out;返回输出流对象的引用,以便支持连续输出操作。

流提取(输入)(重载为全局函数):

代码实现:

//流提取(提取输入到类里面,所以类不能加const)
istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

注意:

  1. 这里的传递过来的对象不能加上const,因为输入本身就是需要改变对象的,所以是不能加上const的

实现逻辑

 
  1. in >> d._year >> d._month >> d._day;这行代码从输入流in中依次读取数据,并分别赋值给Date对象d的年份、月份和日期成员变量。
    • 首先读取一个整数作为年份,存储到d._year中。
    • 接着读取一个整数作为月份,存储到d._month中。
    • 最后读取一个整数作为日期,存储到d._day中。
  2. return in;返回输入流对象的引用,以便支持连续输入操作。

日期类的检查

//这里我们直接重载为内联函数
//检查日期是否合法
bool CheckDate()
{
	//检查月份,天数
	if (_year < 0 || _month < 1 || _month>12
		|| _day < 1 || _day>this->GetmonthDay(_year, _month))
	{
		return false; 
	}
	else
	{
		return true;
	}
}

所以我们可以在哪检查,可以在输入的时候和构造的时候检查,这里我只是在提取流进行检查

//流提取(提取输入到类里面,所以类不能加const)
istream& operator>>(istream& in, Date& d)
{
	while (1)
	{
		cout << "请依次输入年月日(只支持公元前的写法):";
		in >> d._year >> d._month >> d._day;
		if (!d.CheckDate())
		{
			cout << "输入的日期类不合法,请重新输入:";
			d.print();
		}
		else
		{
			break;
		}
	}
	return in;
}

实现逻辑

 
  1. while (1):这是一个无限循环,目的是不断要求用户输入合法的日期,直到输入正确为止。
  2. cout << "请依次输入年月日(只支持公元前的写法):";:提示用户输入日期信息,并明确只支持公元前的写法。
  3. in >> d._year >> d._month >> d._day;:从输入流中读取三个整数,分别存储到Date对象d的成员变量_year(年份)、_month(月份)和_day(日期)中。
  4. if (!d.CheckDate()):调用Date类的成员函数CheckDate()来检查输入的日期是否合法。如果这个函数返回false,说明输入的日期不合法。
    • cout << "输入的日期类不合法,请重新输入:";:如果日期不合法,输出提示信息,要求用户重新输入。
    • d.print();:可能是输出当前输入的不合法日期,以便用户查看并纠正错误。
  5. else:如果日期合法。
    • break;:跳出无限循环。

 代码总结

//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 = 1901, int month = 1, int day = 1);

	//拷贝构造函数
	Date(const Date& d);

	//获取一个日期(内联函数)
	int GetmonthDay(int year, int month)const
	{
		assert(month < 13 && month>0);
		static 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;
		}
		else
		{
			return monthDayArray[month];
		}
	}

	//检查日期是否合法
	bool CheckDate()
	{
		//检查月份,天数
		if (_year < 0 || _month < 1 || _month>12
			|| _day < 1 || _day>this->GetmonthDay(_year, _month))
		{
			return false; 
		}
		else
		{
			return true;
		}
	}

	//运算符重载
	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);
	//打印函数
	void print();
	
	//日期之间相差多少天
	int operator-(const Date& d)const;//这里加上const,就不会因为单参数构造产生调用歧义
private:
	int _year;
	int _month;
	int _day;
};

//Date.cpp实现文件

#include"Date.h"
//构造函数
Date::Date(int year, int month, int day)
	:_year(year)
	, _month(month)
	, _day(day)
{}

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

//打印函数
void Date::print()
{
	cout << _year << "/" << _month << "/" << _day << endl << endl;
}

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

//计算加法
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= day;
	}
	_day += day;
	while (_day > GetmonthDay(_year, _month))
	{
		_day -= GetmonthDay(_year, _month);
		_month += 1;
		if (_month > 12)
		{
			_year += 1;
			_month = 1;
		}
	}
	return *this;
}
Date Date::operator+(int day)const
{
	Date tmp = *this;
	tmp += day;//这里需要注意一个点,不能是this的复用,this的复用会导致自身变化
	return tmp;
}
//日期类的实现-=
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += day;
	}
	_day -= day;
	while (_day <= 0)
	{
		_month -= 1;
		if (_month == 0)
		{
			_year -= 1;
			_month = 12;
		}
		_day += GetmonthDay(_year, _month);
	}
	return *this;
}
Date Date::operator-(int day)const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}
//前置++和后置++
Date& Date::operator++()
{
	return *this += 1;
}
Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}
//前置--和后置--
Date& Date::operator--()
{
	return *this -= 1;
}
Date Date::operator--(int)
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}

//日期之间相差多少天
int Date::operator-(const Date& d)const
{
	//这里采取假设法,假设this是大的,如果不是,则进行转换
	Date max = *this;
	Date min = d;
	int flag = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int cout = 0;
	while (max != min)
	{
		++min;
		++cout;
	}
	return cout* flag;
}

//流插入(输出到屏幕)//给返回值,支持连续赋值,不然只能一次打印一个
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl << endl;
	return out;
}
//流提取(提取输入到类里面,所以类不能加const)
istream& operator>>(istream& in, Date& d)
{
	while (1)
	{
		cout << "请依次输入年月日(只支持公元前的写法):";
		in >> d._year >> d._month >> d._day;
		if (!d.CheckDate())
		{
			cout << "输入的日期类不合法,请重新输入:";
			d.print();
		}
		else
		{
			break;
		}
	}
	return in;
}

//test.cpp测试文件

#include"Date.h"
int main()
{
	//日期类构造函数的测试
	Date d1(111,1,1);
	d1.print();

	//日期类拷贝构造函数的测试
	Date d2(d1);
	d2.print();

	//日期类获取每个月天数的测试
	int ret1 = d2.GetmonthDay(1999, 2);
	cout << ret1 << endl << endl;

	//比较测试(没有问题)
	Date d3(1, 1, 1);
	Date d4(1, 1, 1);
	Date d5(2, 2, 2);
	bool ret = d3.operator==(d4);
	bool ret2 = d3.operator<(d5);
	bool ret3 = d3.operator<=(d4);
	bool ret4 = d5.operator<=(d3);
	bool ret5 = d5.operator<(d3);
	cout << ret << endl << endl;
	cout << ret2 << endl << endl;
	cout << ret3 << endl << endl;
	cout << ret4 << endl << endl;
	cout << ret5 << endl << endl;

	//测试日期类的加等和加
	Date d6;
	d6 += 1000;
	d6.print();
	Date ret6 = d6 + 10000;
	ret6.print();
	//首先,编译器尝试寻找一个可以处理d6 + 10000的操作符重载函数,比如operator + (int),
	//如果没有找到这样的函数。
	//然后,编译器可能会尝试将d6 + 10000解释为d6.operator+(Date(10000)),
	//也就是先通过单参数构造函数将整数10000转换为一个临时的Date对象,
	//然后再尝试调用可能存在的operator + (const Date&)成员函数来执行加法操作。
	//
	// 两个解决办法
	// 1, explicit Date(int value);
	//使用explicit关键字后,编译器将不会自动使用这个单参数构造函数进行隐式类型转换,从而避免了意外的行为。
	// 2,加上const修饰
	//

	//测试日期类的减等和减
	Date d7;
	d7 -= 10000;
	d7.print();
	Date d8(2000,1,1);
	Date ret8 = d8 - 1000; //原因是:1000但参构造成为了Date对象,导致调用不明确 禁止掉可以解决折扣的问题
	ret8.print(); //如果你给那个函数加上了const就只有const对象可以调用  不会出现调用不明确了

	//测试日期类的++和--
	Date d9;
	Date ret9 = d9--;
	ret9.print();
	++d9;
	++d9;
	d9.print();

	//流插入测试
	cout << d9;
	//流提取测试
	Date d10;
	cin >> d10;
	cout << d10;

	//测试日期之间相差多少天
	Date d11(1901, 1, 1);
	Date d12(2000, 3, 1);
	int ret10 = d11 - d12;
	cout << ret10 << endl;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值