C++类和对象之 【日期类的实现】(.h文件中声明,.cpp文件中定义)

目录

1.日期类的预览

2.日期类的具体实现

2.1计算每月的天数

2.2输入输出

2.3构造函数

2.4日期大小的比较

2.5日期+=、+、-=、-天数

2.6++、--日期、日期++、--

2.7日期之间的天数


1.日期类的预览

学习了类和对象这一章节的知识,我们简单地来创建一个日期类

首先我们来整体预览一下日期类的大致结构(在.h头文件中进行声明)

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	static int GetMonthDay(int year, int month);

	Date(int year = 2025, int month = 3, int day = 17);

	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& operator<<(ostream& out, const Date& d);

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

注意到,日期类只包含内置类型,所以

析构函数,拷贝构造函数,赋值重载函数都不用手搓

下面我们开始一项项讲解:

2.日期类的具体实现

2.1计算每月的天数

通过创建一个函数,计算每月的天数

int Date::GetMonthDay(int year, int month)
{
	int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (month == 2)
	{
		if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
			return 29;
		else return 28;
	}
	else
	{
		return days[month];
	}
}

(1)将 GetMonthDay 声明为静态函数的好处:类里类外都可以访问

(1)创建一个数组存放每一个月的天数,判断闰年返回即可

(1)先判断是否是2月,在判断是否是闰年,效率有所提高

2.2输入输出

我们希望 

这样输入一个日期类对象: cin >> d;

这样输出一个日期类对象: cout << d;

显然需要进行运算符重载:

(1)当我们选择将流插入和流提取运算符重载为成员函数

由于this指针是隐藏的第一个参数,即默认的左操作数

那么我们最终的实现只可能是:

d << cout;(打印d)

d >> cin; (输入d)

这显然不符合常规使用

(2)所以我们选择将流插入和流提取运算符重载为全局函数

又注意到:

类的成员变量一般都是私有的,

想要访问,可以直接声明为友元函数突破封装

或者写几个成员函数返回成员变量的值

下面实现友元函数:

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

istream& operator>>(istream& in, Date& d)
{
	int year, month, day;
	in >> year >> month >> day;

	if (month > 0 && month < 13 && day >= 1 
		&& day <= Date::GetMonthDay(year, month))
	{
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}

	return in;
}

(1)ostream、istream对象会在函数体内部进行相应改变,不能用const修饰

(1)流插入运算符重载的时候,用const修饰引用d,防止函数体内部的修改

流提取运算符重载的时候,不用const修饰引用d,因为此时就是要改变d

(1)注意非法日期的输入

(1)为了连续的输入输出,需要返回相应的ostream、istream对象

2.3构造函数

我们选择手搓一个全缺省的构造函数,注意非法日期即可

Date::Date(int year = 2025, int month = 3, int day = 17)
{
	if (month > 0 && month < 13 && day >= 1 && day <= GetMonthDay(year, month))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}
}

2.4日期大小的比较

重点就是:学会函数的复用

只需写一个判断小于的函数和一个判断等于的函数

就可以实现所有大小比较的复用

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

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

(1)判断是否等于时,直接返回表示式!!

(1)因为大小比较时,日期对象不会发生改变,加上const修饰,

使得普通对象和const对象都可以调用该函数

2.5日期+=、+、-=、-天数

这里需要区分: date += day和date + 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)
		{
			_month = 1;
			++_year;
		}
	}

	return *this;
}

Date Date::operator+(int day) const
{
	Date temp = *this;
	temp += day;

	return temp;
}



Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += (-day);
	}

	_day -= day;
	while (_day < 1)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}

		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

Date Date::operator-(int day) const
{
	Date temp = *this;
	temp -= day;

	return temp;
}

(1)同样,学习函数的复用

(1)重载+, 会创建两个临时对象,所以我们选择在 重载+ 时去复用+=

因为如果选择在 重载+= 时去复用+,

调用任意一个运算符都会进行对象的创建,代码效率就会下降

(1)this指针可以在成员函数内部进行使用

2.6++、--日期、日期++、--

Date& Date::operator++()
{
	_day++;
	if (_day > GetMonthDay(_year, _month))
	{
		++_month;
		if (_month == 13)
		{
			_month = 1;
			++_year;
		}
		_day = 1;
	}
	return *this;
}

Date Date::operator++(int)
{
	Date temp = *this;
	++(*this);

	return temp;
}

Date& Date::operator--()
{
	_day--;
	if (_day == 0)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}
		_day = GetMonthDay(_year, _month);
	}
	return *this;
}

Date Date::operator--(int)
{
	Date temp = *this;
	--(*this);

	return temp;
}

(1)this指针在函数体中的使用

(2)临时对象的创建,注意返回值类型即可

2.7日期之间的天数

int Date::operator-(const Date& d) const
{
	Date min = *this;
	Date max = d;
	int flag = -1;

	if (min > max)
	{
		min = d;
		max = *this;
		flag = 1;
	}

	int cnt = 0;
	while (min < max)
	{
		++cnt;
		++min;
	}
	return cnt * flag;
}

 (1)默认大日期、默认小日期,用max、min替换(使代码更简洁)

(2)flag的妙用,天数为正还是负

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值