C++实现日期类(运算符重载)

 

日期类的实现

经历前期C语言的学习,C语言的编程思路是面向过程的编程,将所需要实现的功能封装为每一个功能函数,在主函数中进行调用

C++编程思想是面向对象的编程,相比较于C语言的编程,它更具有更高的安全性和可维护性,C++的特性将功能利用类进行抽象后进行封装,之后在通过创建对象实现功能调用

  • 重载运算符

基于基础C++11标准下新特性,主要通过运算符重载来实现日期类

首先来了解运算符重载的特性:

运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)

注意:
1,不能通过连接其他符号来创建新的操作符:比如operator@

2,重载操作符必须有一个类类型或者枚举类型的操作数

3,用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义

4,作为类成员的重载函数时,有一个默认的形参this,限定为第一个形参

5,.* 、:: 、sizeof  、?:   、.  注意以上5个运算符不能重载

7编译器会默认生成赋值运算符重载,完成值拷贝

  • 日期类

  1. 类成员变量
  2. 类构造函数
  3. 类析构函数
  4. 类拷贝构造函数
  5. +=运算符重载
  6. -=运算符重载
  7. +/-运算符重载
  8. 前置++/--运算符重载
  9. 后置++/--运算符重载
  10. 关系运算符重载(日期比较)
  11. 日期间隔天数计算
  • 类成员变量

日期类中主要以年  月   日   作为成员变量,同时为了实现C++类的封装,将其设定为私有成员变量

private:
	int _y;
	int _m;
	int _d;
  • 类构造函数

为了初始化类对象的创建,编译器默认的构造函数为无参构造函数,这里自定义带默认参数的构造函数初始化类对象

Date(int y = 1900, int m = 1, int d = 1)
	{
		//判断初始化日期是否有效
		if (y <= 0 || m <= 0 || m > 12 || d <= 0 || d > getDay(y,m))
		{
			_y = 1;
			_m = 1;
			_d = 1;
			cout<<"日期无效"<<endl;
		}
		else
		{
			_y = y;
			_m = m;
			_d = d;
		}
	}
  • 类析构函数

由于日期类中,其成员变量均为int整型,构造函数也仅仅为简单的赋值操作,没有开辟内存空间,不需要资源释放,对此析构函数的功能不明显

具体对于析构函数的理解参照构造,析构,拷贝构造核心点总结

  • 类拷贝构造函数

类似于上述析构函数的分析,简单的值拷贝,不涉及内存空间拷贝,对此日期类中拷贝构造函数为浅拷贝

但是需要注意  拷贝构造函数的形参为const引用类型,以免引起值拷贝递归调用

具体对于拷贝构造函数的理解参照构造,析构,拷贝构造核心点总结

Date(const Date& d)
	{
		_y = d._y;
		_m = d._m;
		_d = d._d;
	}
  • +=运算符重载

传入参数为一个int整型的天数

首先判断传入天数是否为一个负数   +=一个负数等于-=一个正数

以类成员变量天数_d加天数判断是否溢出

根据溢出天数进行月份进位  以及年份进位和月份归1

进位过程需要通过一个while循环判断,判断条件为天数<当前月份天数结束循环

int getDay(int y, int m)
	{
		static int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		int day = days[m];
		if (m == 2 && (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)))
		{
			day += 1;//二月 闰年  多一天 29 
		}
		return day;
	}

	Date& operator+=(int day)//日期+=运算
	{
		//判断日期是否为负数
		if (day < 0)
		{
			return *this -= -day;
		}
		_d += day;
		//判断天数是否溢出
		while (_d > getDay(_y, _m))
		{
			_d -= getDay(_y,_m);//计算溢出天数
			//月份进位
			_m++;
			if (_m == 12)
			{
				_y++;
				_m = 1;//月份归1,年份进位
			}
		}
		return *this;//左操作数即为this指针指向
	}
  • -=运算符重载

传入参数为一个int整型的天数

首先判断传入天数是否为一个负数   -=一个负数等于+=一个正数

以类成员变量天数_d减去天数判断是否需要前一个月的天数来进行补偿

根据所需补偿天数进行月份退位  以及年份退位和月份归12

由于需要前一个月天数来补偿,所以先考虑退位,再进行补偿天数计算

进位过程需要通过一个while循环判断,判断条件为天数>0结束循环

Date& operator-=(int day)//日期-=运算
	{
		//判断日期是否为负数
		if (day < 0)
		{
			return *this += -day;
		}
		_d -= day;
		//判断天数是否为负数
		while (_d < 0)
		{
			//月份退位,前一个月的天数来进行补偿
			_m--;
			if (_m == 0)
			{
				_y--;
				_m = 12;//月份归12,年份退位
			}
			_d += getDay(_y, _m);//计算补偿天数
		}
		return *this;//左操作数即为this指针指向
	}
  • +/-运算符重载

日期的加减操作,其需要注意,左操作数不为返回值,所需左操作数不会被修改,需要创建新对象作为返回值 进行值传递

Date operator+(int day)//日期+运算   d=d1+90;  d1本身不会被修改  而是值传递
	{
		Date tmp = *this;
		
		return tmp += day;//+=操作重载
	}

	Date operator-(int day)//日期-运算   d=d1-90;  d1本身不会被修改  而是值传递
	{
		Date tmp = *this;

		return tmp -= day;//+=操作重载
	}
  • 前置++/--运算符重载

自加运算符自身改变,所以返回类型为引用,且参数为默认this指针,返回this指针解引用+1或-1

//前置++
	Date& operator++()//本身改变  可以返回引用
	{
		return *this += 1;
	}


	//前置--
	Date& operator--()//本身改变  可以返回引用
	{
		return *this -= 1;
	}
  • 后置++/--运算符重载

后置自加操作,自身先不改变,等传值结束后,再进行加1操作

this指向左操作数 左操作数先赋值后才会改变  需要创建临时对象作为返回值

//后置++  与前置++构成重载  参数加入int
	Date operator++(int)
	{
		Date tmp = *this;
		*this += 1;
		return tmp;
	}
	//后置--  与前置--构成重载  参数加入int
	Date operator--(int)
	{
		Date tmp = *this;
		*this -= 1;
		return tmp;
	}
  • 关系运算符重载(日期比较)

关系判断包括  ==   !=    >    <     >=    <=

其中形参包括隐含this和显示创建的常引用类型d

返回值为bool类型  作为关系判断条件

bool operator==(const Date& d)
	{
		return _y == d._y&&_m == d._m&&_d == d._d;
	}

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

	bool operator>(const Date&d)
	{
		if (_y > d._y)
		{
			return true;
		}
		else if (_y == d._y)
		{
			if (_m > d._m)
				return true;
			else if (_m == d._m)
			{
				if (_d > d._d)
				{
					return true;
				}
			}
		}
		return false;
	}

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

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

	bool operator<=(const Date& d)
	{
		return !(*this >= d);
	}
  • 日期间隔天数计算

综合之前所写的运算符重载函数包括++  +=  -=  --等,再次基础上完成

相隔天数计算:小日期经过多少次自加与大日期相同

//日期相减  相差天数
	int operator-(const Date& d)
	{
		//小日期经过多少次自加与大日期相同
		Date max = *this;
		Date min = d;
		int flag = 1;
		if (max < min)
		{
			max = d;
			min = *this;
			flag = -1;
		}
		int day = 0;
		while (min < max)
		{
			++min;
			++day;
		}
		return flag * day;
	}
  • 整体代码如下:

#include<iostream>

using namespace std;

class Date
{
public:
	Date(int y = 1900, int m = 1, int d = 1)
	{
		//判断初始化日期是否有效
		if (y <= 0 || m <= 0 || m > 12 || d <= 0 || d > getDay(y,m))
		{
			_y = 1;
			_m = 1;
			_d = 1;
			cout<<"日期无效"<<endl;
		}
		else
		{
			_y = y;
			_m = m;
			_d = d;
		}
	}

	Date(const Date& d)
	{
		_y = d._y;
		_m = d._m;
		_d = d._d;
	}

	~Date()
	{
		
	}


	int getDay(int y, int m)
	{
		static int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		int day = days[m];
		if (m == 2 && (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)))
		{
			day += 1;//二月 闰年  多一天 29 
		}
		return day;
	}

	Date& operator+=(int day)//日期+=运算
	{
		//判断日期是否为负数
		if (day < 0)
		{
			return *this -= -day;
		}
		_d += day;
		//判断天数是否溢出
		while (_d > getDay(_y, _m))
		{
			_d -= getDay(_y,_m);//计算溢出天数
			//月份进位
			_m++;
			if (_m == 12)
			{
				_y++;
				_m = 1;//月份归1,年份进位
			}
		}
		return *this;//左操作数即为this指针指向
	}

	Date& operator-=(int day)//日期-=运算
	{
		//判断日期是否为负数
		if (day < 0)
		{
			return *this += -day;
		}
		_d -= day;
		//判断天数是否为负数
		while (_d < 0)
		{
			//月份退位,前一个月的天数来进行补偿
			_m--;
			if (_m == 0)
			{
				_y--;
				_m = 12;//月份归12,年份退位
			}
			_d += getDay(_y, _m);//计算补偿天数
		}
		return *this;//左操作数即为this指针指向
	}

	Date operator+(int day)//日期+运算   d=d1+90;  d1本身不会被修改  而是值传递
	{
		Date tmp = *this;
		
		return tmp += day;//+=操作重载
	}

	Date operator-(int day)//日期-运算   d=d1-90;  d1本身不会被修改  而是值传递
	{
		Date tmp = *this;

		return tmp -= day;//+=操作重载
	}
	//前置++
	Date& operator++()//本身改变  可以返回引用
	{
		return *this += 1;
	}


	//前置--
	Date& operator--()//本身改变  可以返回引用
	{
		return *this -= 1;
	}

	//后置++  与前置++构成重载  参数加入int
	Date operator++(int)
	{
		Date tmp = *this;
		*this += 1;
		return tmp;
	}
	//后置--  与前置--构成重载  参数加入int
	Date operator--(int)
	{
		Date tmp = *this;
		*this -= 1;
		return tmp;
	}


	bool operator==(const Date& d)
	{
		return _y == d._y&&_m == d._m&&_d == d._d;
	}

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

	bool operator>(const Date&d)
	{
		if (_y > d._y)
		{
			return true;
		}
		else if (_y == d._y)
		{
			if (_m > d._m)
				return true;
			else if (_m == d._m)
			{
				if (_d > d._d)
				{
					return true;
				}
			}
		}
		return false;
	}

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

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

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

	//日期相减  相差天数
	int operator-(const Date& d)
	{
		//小日期经过多少次自加与大日期相同
		Date max = *this;
		Date min = d;
		int flag = 1;
		if (max < min)
		{
			max = d;
			min = *this;
			flag = -1;
		}
		int day = 0;
		while (min < max)
		{
			++min;
			++day;
		}
		return flag * day;
	}
	int getyear()
	{
		return _y;
	}
	int getmonth()
	{
		return _m;
	}
	int getday()
	{
		return _d;
	}
private:
	int _y;
	int _m;
	int _d;
};

void test()
{
	Date d1(2021,2,4);
	Date d2(2021, 2, 4);
	Date d3(2021, 2, 4);
	Date d4(2021, 2, 4);
	cout << "当前日期为:" << d1.getyear() << "-" << d1.getmonth() << "-" << d1.getday() << endl;
	d1 += 1;
	cout << "当前日期后1天为:" << d1.getyear() << "-" << d1.getmonth() << "-" << d1.getday() << endl;
	d2 += 30;
	cout << "当前日期后30天为:" << d2.getyear() << "-" << d2.getmonth() << "-" << d2.getday() << endl;
	d3 += 90;
	cout << "当前日期后90天为:" << d3.getyear() << "-" << d3.getmonth() << "-" << d3.getday() << endl;
	d4 += 360;
	cout << "当前日期后360天为:" << d4.getyear() << "-" << d4.getmonth() << "-" << d4.getday() << endl;
	Date d5(2021, 2, 5);
	Date d6(2021, 2, 5);
	Date d7(2021, 2, 5);
	Date d8(2021, 2, 5);
	cout << "当前日期为:" << d5.getyear() << "-" << d5.getmonth() << "-" << d5.getday() << endl;
	d5 -= 1;
	cout << "当前日期前1天为:" << d5.getyear() << "-" << d5.getmonth() << "-" << d5.getday() << endl;
	d6 -= 30;
	cout << "当前日期前30天为:" << d6.getyear() << "-" << d6.getmonth() << "-" << d6.getday() << endl;
	d7 -= 90;
	cout << "当前日期前90天为:" << d7.getyear() << "-" << d7.getmonth() << "-" << d7.getday() << endl;
	d8 -= 360;
	cout << "当前日期前360天为:" << d8.getyear() << "-" << d8.getmonth() << "-" << d8.getday() << endl;
	Date d9(2021, 2, 6);
	Date d10(2021, 2, 6);
	Date d11(2021, 2, 6);
	Date d12(2021, 2, 6);
	cout << "当前日期为:" << d9.getyear() <<"-"<< d9.getmonth() << "-" << d9.getday() << endl;
	//前置++
	d10 = ++d9;//d10 与 d9++后 结果保持一致
	cout << "当前日期前置增加1天为:" << d10.getyear() << "-" << d10.getmonth() << "-" << d10.getday() << endl;
	//后置++
	d12 = d11++;//d2 与d11++前结果一致   d11自身加1
	cout << "当前日期后置增加1天为:" << d12.getyear() << "-" << d12.getmonth() << "-" << d12.getday() << endl;
	Date d13(2020, 1, 6);
	Date d14(2021, 2, 6);
	cout << "日期:" << d13.getyear() << "-" << d13.getmonth() << "-" << d13.getday() << "与日期:" << d14.getyear() << "-" << d14.getmonth() << "-" << d14.getday() << "相隔天数为:" << d14-d13 << endl;
}

int main()
{
	test();
}
  • 测试结果如下

 

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HT . WANG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值