完整地实现日期类(分3个文件+测试结果)

🌈完整地实现日期类

👻主要使用了构造函数、运算符重载函数。
👻以下日期类包含接收日期、日期与日期减加减、日期与天数间加减、日期自增减(自动加减一天)、日期间大小比较等功能。

☀️一、分析与优化各函数实现

其实没有必要将所有赋值运算符重载都完整地写出来,有很多函数的实现逻辑其实是有大关联的:

对于日期类的赋值运算符重载,可有以下分组:
①operator== & operator!=;二者可逻辑取反。
②operator+ & operator+= ;一个在另一个基础上。
③operator- & operator-=;一个在另一个基础上。
④operator++ & operator++(int) & operator-- & operator–(int);后置的比前置的多了个整型参数
⑤operator> & operator<= & operator< & operator>=;可以多次逻辑取反。

🎈1.operator== & operator!=

先写==,!=即为==的逻辑取反

//判断是否相等
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);
}

🎈2.operator> & operator<= & operator< & operator>=

最开始只用写一个函数即可,比如>,剩下的函数都可以复用这个函数了,即:>函数的取反是<=函数;>的结果并上==的结果就得到>=函数;>=函数的取反是<函数。

//判断是否大于
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)) {
		if (_day > d._day)
			return true;
		}
	return false;
}
//判断是否小于等于 
bool Date::operator<=(const Date& d) {
	return !(*this > d);
}
//判断是否大于等于 
bool Date::operator>=(const Date& d) {
	return *this == d || *this > d;
}
//判断是否小于 
bool Date::operator<(const Date& d) {
	return !(*this >= d);
}

🎈3.operator+ & operator+=

可以先写+函数,在+函数的基础上复用+函数得到+=函数;也可以先写+=再写+,到底选择哪一种方式呢?选拷贝构造次数少的方式,如下方分析:

🌟(1)先写+=函数,复用+=函数得到+函数
//日期+=天数
Date& Date::operator+=(int x) {
	if(x<0){
	return *this-=x;
	}
	_day += x;
	while (_day > GetMonthDay(_year,_month)) {
		_day -= GetMonthDay(_year,_month);
		_month++;
		if (_month > 12) {
			_month = 1;
			_year++;
		}
	}
	return *this;
}
//(在+=函数的基础上实现)日期+天数
Date Date::operator+(int x) {
	Date tmpd(*this);
	tmpd += x;
	return tmpd;
}

+=函数中拷贝构造对象次数:0(未涉及拷贝构造对象,且传引用返回,一共拷贝构造了0次)

+=函数中拷贝构造对象次数:2(+在+=的基础上,因此先拷贝复制了0次;之后又拷贝构造了tmpd对象,返回tmpd时用的传值返回,一共拷贝构造了2次)

🌟(2)先写+函数,复用+函数得到+=函数
//日期+天数
Date Date::operator+(int x) {
		if(x<0){
		return *this-x;
		}
		Date tmpd(*this);
		tmpd._day += x;
		while(tmpd._day > GetMonthDay(tmpd._month)) {
			tmpd._day -= GetMonthDay(tmpd._month);
			tmpd._month++;
			if (tmpd._month > 12) {
				tmpd._month = 1;
				tmpd._year++;
			}
		}
		return tmpd;
		}
//(在+函数的基础上实现)日期+=天数
Date& Date::operator+=(int x) {
		*this = *this + x;
		return *this;
}

+函数中拷贝构造对象次数:2(用this指针拷贝构造对象、传值返回了类对象,一共拷贝构造了2次)

+=函数中拷贝构造对象次数:3(由于+=在+的基础上,因此先拷贝复制了2次;然后又给this对象赋值了一次,一共拷贝构造了3次)

确定谁复用谁的意义:对于日期类对象,二者拷贝对象次数的差异可能影响不大,但是换一个庞大的类类型,拷贝构造动作会用掉很多空间,会降低效率,因此会产生巨大差异

👻最优方式:先写+=函数,再复用+=函数得到+函数。尽量少地进行拷贝构造动作

🎈4.operator- & operator-=

与+=和+函数同理,最优方式是先写-=函数,再复用-=函数得到-函数。

//日期-=天数=新日期(本身)
Date& Date::operator-=(int x) {
	if(x<0){
	    return *this+=x;
	}
	_day -= x;
	if (_day > 0) {
		return *this;
	}
	else if (_day == 0) {
		_month--;
		if (_month == 0) {
			_month = 12;
			_year--;
		}
		_day = GetMonthDay(_year,_month);
		return *this;
	}
	else {   //tmp._day<0
		while (_day < 0) {
			_month--;
			_day = GetMonthDay(_year,_month) + _day;
			if (_day == 0) {
				_month--;
				if (_month == 0) {
					_month = 12;
					_year--;
				}
				_day = GetMonthDay(_year,_month);
			}
		}
		return *this;
	}
}
//日期-天数=日期(拷贝)
Date Date::operator-(int x) {
	Date tmp(*this);
	tmp -= x;
	return tmp;
}

🎈5.一个特殊的减法重载:日期-日期=天数

对于日期而言,加法这个运算操作一般用于在日期的基础上加天数,得到推算出的日期,很少有两个日期相加的运算;
而减法可以用于日期间天数,得到倒退的日期,还可以日期减日期,得到二者相差多少天

问:是“否日期-日期=天数”的这个重载和operator-重载冲突?
答:不会,因为二者的参数一个是Date类日期对象,另一个是整型数值,返回值一个是整型数值,另一个是Date类日期对象。编译器可以根据函数调用匹配到正确的函数重载。

相减思路:
现有两个日期,需要算出二者间相隔多少天。
1.比较出两个日期中较大的那一个,大的赋值给max对象,小的赋值给min对象;
2.算出大日期是那一年的第几天,记为pass变量;
3.算出小日期距离那一年末还有多少天,记为to变量;
4.得出两日期间相差多少天(算出两日期间完整的年份的天数和,加pass,再加to)

//日期-日期=天数
int Date::operator-(const Date& d) {
	//1.比较出两个日期中较大的一个
	Date max(1, 1, 1);
	Date min(1, 1, 1);
	if (*this > d) {
		max = *this;
		min = d;
	}
	else if (*this == d)
		return 0;
	else {
		max = d;
		min = *this;
	}
	//2.算出大日期是那一年的第几天
	int pass = 0;
	pass += max._day;
	for (int i = 1;i < max._month;i++) {
		pass += GetMonthDay(max._year,i);
	}
	//3.算出小日期距离那一年末还有多少天
	int yearDay = GetYearDay(min._year);
	int now = 0;
	for (int i = 1;i < min._month;i++) {
		now += GetMonthDay(min._year,i);
	}
	now += min._day;
	int to = yearDay - now;
	//4.得出两日期间相差多少天
	min._year++;
	if (min._year > max._year) {
		int tmp = GetYearDay(max._year);
		return pass + to - tmp;
	}
	int tmp = 0;
	for (int i = min._year;i < max._year;i++) {
		tmp += GetYearDay(i);
	}
	return pass + to + tmp;
}

🎈6.operator++ & operator++(int) & operator-- & operator–(int)

前置++和后置++的区别(–同理):
(1)前置++表示先++后使用,即变量内的值马上+1,后续使用得到的都是+1后的值;
(2)后置++表示先使用后++,即先使用变量原来的值,使用完后马上+1;
(3)前置++效率更高,因为后置++还需要多一次拷贝。对于内置类型二者差异不大,但对于自定义类型最好用前置,减少拷贝的次数

规定:为了和++d1区分,d1++无参数,而d1++的函数,参数必须为int。

//前置++(日期自动+1天)
Date& Date::operator++() {
	*this += 1;
	return *this;
}
//后置++(日期自动+1天)
Date Date::operator++(int) {
	Date tmp(*this);
	*this += 1;
	return tmp;
}

//前置--(日期自动-1天)
Date& Date::operator--() {
	*this -= 1;
	return *this;
}
//后置--(日期自动-1天)
Date Date::operator--(int) {
	Date tmp(*this);
	*this -= 1;
	return tmp;
}

☀️二、完整Date类实现和Test、main函数

注意:
1.析构和拷贝构造函数对于日期类而言不用写。
2.分文件时,.cpp文件中存放的函数实现需要指定类域。
3.对于缺省参数,为了防止声明与定义的参数默认值不一致,只能在声明时给出。

🎈1.Date.h头文件

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Date {
private:
	int _year;
	int _month;
	int _day;
public:
	//构造函数
	Date(int year, int month, int day);
	//析构函数、拷贝构造函数不用显式写

	//得到某月的总天数
	int GetMonthDay(int year, int month)const;
	//得到某年的总天数
	int GetYearDay(int year)const;
	//打印日期
	void Print()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;

	//日期+天数
	/*Date operator+(int x);
	//(在+函数的基础上实现)日期+=天数
	/*Date& operator+=(int x);*/

	//日期+=天数
	Date& operator+=(int x);
	//(在+=函数的基础上实现)日期+天数
	Date operator+(int x)const;

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

	//日期-=天数=新日期(本身)
	Date& operator-=(int x);
	//日期-天数=日期(拷贝)
	Date operator-(int x)const;

	//前置++(日期自动+1天)
	Date& operator++();
	//后置++(日期自动+1天)
	Date operator++(int);

	//前置--(日期自动-1天)
	Date& operator--();
	//后置--(日期自动-1天)
	Date operator--(int);
};

🎈2.Date.cpp函数定义

#include"Date.h"
//构造函数
Date::Date(int year, int month, int day) {
	_year = year;
	_month = month;
	_day = day;
	//同时完善日期检查功能
	if (_year < 1 ||
		_month < 1 || _month > 12 ||
		_day < 1 || _day > GetMonthDay(_year,_month)){
		cout << "日期错误" << endl;
		return;
	}
}
//得到某月的总天数
int Date::GetMonthDay(int year,int month)const {
	int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		arr[2] = 29;
	return arr[month];
}
//得到某年的总天数
int Date::GetYearDay(int year) const {
	if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		return 366;
	return 365;
}

//打印日期
void Date::Print() const {
	cout << _year << "年" << _month << "月" << _day << "日" << 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 {
	return !(*this == d);
}

//判断是否大于
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)) {
		if (_day > d._day)
			return true;
		}
	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);
}

//日期+=天数
Date& Date::operator+=(int x) {
	_day += x;
	while (_day > GetMonthDay(_year,_month)) {
		_day -= GetMonthDay(_year,_month);
		_month++;
		if (_month > 12) {
			_month = 1;
			_year++;
		}
	}
	return *this;
}
//(在+=函数的基础上实现)日期+天数
Date Date::operator+(int x) const {
	Date tmpd(*this);
	tmpd += x;
	return tmpd;
}


	//日期-日期=天数
int Date::operator-(const Date& d) const {
	//1.比较出两个日期中较大的一个
	Date max(1, 1, 1);
	Date min(1, 1, 1);
	if (*this > d) {
		max = *this;
		min = d;
	}
	else if (*this == d)
		return 0;
	else {
		max = d;
		min = *this;
	}
	//2.算出大日期是哪一月的第几天
	int pass = 0;
	pass += max._day;
	for (int i = 1;i < max._month;i++) {
		pass += GetMonthDay(max._year,i);
	}
	//3.算出小日期距离那一年末还有多少天
	int yearDay = GetYearDay(min._year);
	int now = 0;
	for (int i = 1;i < min._month;i++) {
		now += GetMonthDay(min._year,i);
	}
	now += min._day;
	int to = yearDay - now;
	//4.得出两日期间相差多少天
	min._year++;
	if (min._year > max._year) {
		int tmp = GetYearDay(max._year);
		return pass + to - tmp;
	}
	int tmp = 0;
	for (int i = min._year;i < max._year;i++) {
		tmp += GetYearDay(i);
	}
	return pass + to + tmp;
}


//日期-=天数=新日期(本身)
Date& Date::operator-=(int x) {
	_day -= x;
	if (_day > 0) {
		return *this;
	}
	else if (_day == 0) {
		_month--;
		if (_month == 0) {
			_month = 12;
			_year--;
		}
		_day = GetMonthDay(_year,_month);
		return *this;
	}
	else {   //tmp._day<0
		while (_day < 0) {
			_month--;
			_day = GetMonthDay(_year,_month) + _day;
			if (_day == 0) {
				_month--;
				if (_month == 0) {
					_month = 12;
					_year--;
				}
				_day = GetMonthDay(_year,_month);
			}
		}
		return *this;
	}
}
//日期-天数=日期(拷贝)
Date Date::operator-(int x) const {
	Date tmp(*this);
	tmp -= x;
	return tmp;
}


//前置++(日期自动+1天)
Date& Date::operator++() {
	*this += 1;
	return *this;
}
//后置++(日期自动+1天)
Date Date::operator++(int) {
	Date tmp(*this);
	*this += 1;
	return tmp;
}

//前置--(日期自动-1天)
Date& Date::operator--() {
	*this -= 1;
	return *this;
}
//后置--(日期自动-1天)
Date Date::operator--(int) {
	Date tmp(*this);
	*this -= 1;
	return tmp;
}


🎈3.Test.cpp测试

#include"Date.h"
int main() {
	Date d1(2024, 1, 31);
	Date d2(2000, 2, 12);
	Date d3(d1);

	int flag = 0;
	//测试==和!=
	if (d1 == d2)
		flag = 1;
	if (d1 != d2)
		flag = 2;
	cout << flag << endl;   //2
	//测试>、<
	if (d1 > d2)
		flag = 3;
	if (d1 <= d2)
		flag = 4;
	cout << flag << endl;   //3
	//测试>=、<=
	if (d1 >= d3)
		flag = 5;
	if (d1 < d3)
		flag = 6;
	cout << flag << endl;   //5
	//计算+、+=
	Date a = d2 + 5;
	a.Print();   //2000年2月17日
	Date b = d2 + 55;
	b.Print();   //2000年4月7日

	d2.Print();  //2000年2月12日
	d2 += 5;
	d2.Print();  //2020年2月17日
	d2 += 55;    
	d2.Print();  //2020年4月12日


	
	//计算-、-=
	Date c = d2 - 55;
	c.Print();   //2000年2月17日
	Date d = d2 - 5;
	d.Print();   //2000年4月7日
	
	d2.Print();  //2020年4月12日
	d2 -= 55;
	d2.Print();  //2000年2月17日
	d2 -= 5;
	d2.Print();  //2000年2月12日



	//计算两日期相隔多少天
	int x = d1 - d2;
	cout << x << endl;   //8754


	//测试前置++、后置++
	Date tmp1(d2++);
	tmp1.Print();  //2000年2月12日
	d2.Print();    //2000年2月13日

	Date tmp2(++d2);
	tmp2.Print();  //2000年2月14日
	d2.Print();    //2000年2月14日

	//测试前置--、后置--
	Date tmp3(d2--);
	tmp3.Print();  //2000年2月14日
	d2.Print();    //2000年2月13日

	Date tmp4(--d2);
	tmp4.Print();  //2000年2月12日
	d2.Print();    //2000年2月12日
}

🎈测试结果

经验证,是正确的。
在这里插入图片描述

  • 17
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值