C++类和对象(5)--日期类的实现

   

目录

1.头文件Date.h

 2.函数实现文件Date.cpp

2.1说明‘-’复用'-='和‘-='复用‘-’的区别

2.2前置++和后置++的说明

3.测试代码Test.cpp 


    下面通过实现日期类来复习使用类和对象的知识,其中每个接口的讲解和知识点的分析写在了代码中的注释中。

1.头文件Date.h

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;

class Date
{
	//友元声明,通过友元声明使全局函数能访问Date类的私有变量
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);

    //void operator<<(ostream& out)
	//{
	//	out << _year << "年" << _month << "月" << _day << "日" << endl;
	//}
	//写成成员函数,<<操作符的左操作数是this,右操作数是out
	//调用时要写成下列形式:
	//d1 << cout;
	//d1.operator<<(cout);
	//返回值为void不支持连续的调用
	//所以写成全局函数较好

public:
	// 全缺省的构造函数,这里缺省值写在声明中,定义中不用写
	Date(int year = 1900, int month = 1, int day = 1);

	//打印函数,因为该函数不会对对象进行修改,所以用const修饰
	void Print() const;

	//检查日期是否为有效日期的函数
	bool CheckDate();

	//获取对应天数的函数
    //因为该函数短小且经常被调用,写在这默认为内联函数,可以减少函数栈帧的开销
	int  GetMonthDay(int year, int month)
	{
		assert(month < 13 && month > 0);

		//定义数组用于获取天数
		static int monthDayArray[] = { -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];
		}
	}

	//由于日期类是没有涉及到资源的申请,所以拷贝构造和赋值运算符重载
	// 都是浅拷贝,可以不需要自己实现,可以使用编译器自动生成的
    //但是声明中写了,就需要实现,下面在Date.cpp文件中进行实现
	// 拷贝构造函数
	Date(const Date& d);
	 赋值运算符重载
	Date& operator=(const Date& d);
	//析构函数,没有资源申请不用实现 
	//~Date();

	//逻辑运算符重载, 先实现一个小于和一个等于,其他的复用这两个进行实现
	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;

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

	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);

	// 前置--
	Date& operator--();
	// 后置--
	Date operator--(int);
private:
	int _year;
	int _month;
	int _day;
};

//ostream 和 istream不支持拷贝构造,不能传值
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

 2.函数实现文件Date.cpp

#include "Date.h"

//不同文件中进行成员函数的声明和定义时,在定义的文件中函数名要加上类名

//检查日期是否为有效日期的函数
bool Date::CheckDate()
{
	//天数不能大于对应月的最大天数且大于0
	//月数不能大于12且不能小于0
	if (_month < 1 || _month > 12
		|| _day < 1 || _day > GetMonthDay(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}

}

// 全缺省的构造函数
Date::Date(int year, int month, int day)	//定义和声明中只有一处给默认值,建议在声明中给
{
	_year = year;
	_month = month;
	_day = day;

	if (!CheckDate())
	{
		cout << "非法日期" << endl;
		Print();
	}
}

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

// 拷贝构造函数    这里的拷贝构造和赋值运算符重载可以不用自己实现
 Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

 赋值运算符重载
Date& Date::operator=(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;

	return *this;
}

//逻辑运算符重载, 先实现一个小于和一个等于,其他的复用这两个进行实现
bool Date::operator==(const Date& d) const
{
	if (_year == d._year
		&& _month == d._month
		&& _day == d._day)
	{
		return true;
	}
	else
	{
		return false;
	}
}

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)
		{
			if (_day < d._day)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
	}
	else
	{
		return false;
	}
}

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

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

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

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

// 日期+=天数
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		*this -= (-day);
		return *this;
	}
	//先加天数,超过当前月的天数进位,再加月数,超过12之后向前进位
	day = _day + day;
	while (day > GetMonthDay(_year, _month))
	{
		day -= GetMonthDay(_year, _month);	//天数先减,因为这个天数取的是当前月的天数,不是下一个月的天数
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	_day = day;

	return *this;
}

// 日期+天数
Date Date::operator+(int day) const
{
	Date tmp = *this;
	tmp += day;
	return tmp;
}

// 日期-=天数
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		*this += (-day);
		return *this;
	}
	while (_day <= day)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	_day = _day - day;

	return *this;
}

// 日期-天数
Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

//日期 - 日期 = 天数
int Date::operator-(const Date& d) const
{
	Date max = *this;
	Date min = d;
	int flag = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int count = 0;
	while (min != max)
	{
		min += 1;
		count++;
	}

	return count * flag;
}

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

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

//ostream 和 istream不支持拷贝构造,不能传值
ostream& operator<<(ostream& out, const Date& d)
{
	cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;

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

2.1说明‘-’复用'-='和‘-='复用‘-’的区别

        这段代码是自己实现'-='功能,'-'通过复用'-='来实现。

// 日期-=天数
Date& Date::operator-=(int day) 
{
	if (day < 0)
	{
		return *this += -day;
	}
	_day -= day;
	while (_day <= 0) //为0也要借
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}

		_day += GetMonthDay(_year, _month); //借上个月的天数
	}

	return *this;
}
// 日期-天数 
Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;

	return tmp;
}

         这段代码是自己实现'-'功能,'-='通过复用'-'来实现。

// 日期-=天数
Date& Date::operator-=(int day)
{
	*this = *this - day;

	return *this;
}
// 日期-天数 
Date Date::operator-(int day) 
{
	Date tmp = *this;
	tmp._day -= day;
	if (day < 0)
	{
		return tmp += -day;
	}
	tmp._day -= day;
	while (_day <= 0) //为0也要借
	{
		--tmp._month;
		if (tmp._month == 0)
		{
			tmp._month = 12;
			--tmp._year;
		}

		tmp._day += GetMonthDay(tmp._year, tmp._month); //借上个月的天数
	}


	return tmp;
}

情况1:

 -= 自己实现:全程没有拷贝

 - 复用 -= : 在创建tmp时和返回临时变量tmp时有两次拷贝

情况2:

 - 自己实现: 全程只有在创建tmp时和返回临时变量tmp时有两次拷贝

 -= 复用 - :复用 - 时有两次拷贝,还有一次赋值则有一次拷贝,故有3次拷贝

上述两种情况对比:

对于 - 来说,情况1和情况2都有两次拷贝

对于 -= 来说,情况2比情况1多了3次拷贝

        区别:上述的两个情况只有在使用'-='这个接口时有区别,就是自己实现'-='会少3次拷贝,效率更高。所以以后我们先实现'-=',然后'-'的实现复用'-='进行实现。

2.2前置++和后置++的说明

         这里解释一下前置++和后置++的区别,前置--和后置++类似,这里不做解释。

// 前置++
Date& Date::operator++()
{
	//先++在用
	*this += 1;
	//返回值返回后给表达式用的,前置++和后置++都要改变*this的值
	//前置++,先++后返回++后的值给表达式用
	return *this;
}
// 后置++
Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	//后置++,++之后返回++之前的值给表达式用
	return tmp;
}

3.测试代码Test.cpp

#include "Date.h"

void test1()
{
	//测试默认构造函数
	Date d1;
	d1.Print();

	Date d2(2024, 8, 26);
	d2.Print();

	Date d3(2024, 8, 34);
	cout << d3.CheckDate() << endl;

	测试获得每个月的对应天数
	//cout << d3.GetMonthDay(2019, 2) << endl;
}

void test2()
{
	//测试拷贝构造和赋值运算符
	Date d1(2024, 8, 26);
	d1.Print();

	Date d2 = d1;
	d2.Print();

	Date d3;
	d3 = d1;
	d3.Print();
}

void test3()
{
	//测试逻辑运算符
	Date d1(2024, 8, 31);
	Date d2(2024, 8, 26);
	Date d3 = d2;

	cout << (d2 == d1) << endl;
	cout << (d2 < d1) << endl;
	cout << (d2 <= d1) << endl;
	cout << (d2 > d1) << endl;
	cout << (d2 >= d1) << endl;
	cout << (d2 != d1) << endl;

	cout << (d2 == d3) << endl;
	cout << (d2 < d3) << endl;
	cout << (d2 <= d3) << endl;
	cout << (d2 > d3) << endl;
	cout << (d2 >= d3) << endl;
	cout << (d2 != d3) << endl;
}

void test4()
{
	//测试日期的加减
	//测试+=
	Date d1(2024, 8, 24);

	d1 += -2000;
	d1.Print();

	//测试+
	Date d2(2024, 8, 26);
	d2 = d2 + 1000;
	d2.Print();

	//测试-=
	Date d3(2024, 8, 26);
	d3 -= (-2000);
	d3.Print();

	//测试-
	Date d4(2024, 8, 31);
	d4 = d4 - 100;
	d4.Print();

	//测试日期 - 日期
	Date d5(2024, 8, 26);
	Date d6(2027, 1, 1);
	cout << (d5 - d6) << endl;
}

void test5()
{
	//测试++和--
	Date d1;
	Date d2(d1);

	Date ret1 = ++d1;
	d1.Print();
	ret1.Print();

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

	Date d3;
	Date d4(d3);

	Date ret3 = --d3;
	d3.Print();
	ret3.Print();

	Date ret4 = d4--;
	d4.Print();
	ret4.Print();
}

void test6()
{
	//测试输入输出
	Date d1;
	Date d2;
	cin >> d1 >> d2;
	cout << d1 << d2 << endl;

}

int main()
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	//test6();
	return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值