日期类计算器的实现以及运算符重载

2023-03-31 09:08:10 浏览数 (1)

前言

 众所周知,运算符重载是C 类与对象中非常重要的一环。今天我们介绍内容就是通过模拟实现日期类的计算机,来详细的了解运算符是如何重载的。

注:代码给在文末。


目录

前言

创建一个日期类

1、重载 == 号

2、重载 > 号

3、复用重载后的  > 和 == 来重载 >= 、!= 、< 、<=  

4、重载 = 号

5、重载 号

6、重载  -= 号

7、重载 - 号

8、前置 和后置 的重载

9、前置--和后置--的重载

10、- 号的再次重载:两个日期类相减

11、 << 和 >> 号的重载。

全篇代码


创建一个日期类

大致步骤可以分为以下:

1、构建一个 Date 日期类,需要有三个成员变量:年、月、日。

        2、写一个构造函数,将传入的年月日的数据利用起来。

代码:

代码语言:javascript复制
#include <iostream>
using namespace std;

class Date
{
public:
	Date(const int year = 1, const int month = 1, const int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

1、重载 == 号

这一步非常简单,我们只需要判断年月日是否都相等就可以了。

代码:

代码语言:javascript复制
bool Date::operator==(const Date& d) const
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

2、重载 > 号

我们需要先比较年,再比较月,最后比较日。

思路:

  1、先比较年,如果年大于,返回 true。

        2、如果年相等,再比较月,如果月大于,返回 true。

        3、如果年和月都相等,最后比较日,如果日大于,返回 true。

代码:

代码语言:javascript复制
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;
	}
	return false;
}

3、复用重载后的  > 和 == 来重载 >= 、!= 、< 、<=  

我们如果还去考虑其中的逻辑去重载剩下的判断符,那么需要的时间成本会很高,我们只需要复用前面写的符号,可以让我们大大节约时间成本。

代码:

代码语言:javascript复制
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);
}

4、重载 = 号

我们可以先让日加上我们需要 = 的天数。这时候我们还需要写一个函数GetMonthDay获取一个月的天数,当类的日大于当月天数的时候,月份 ,天数减去当月天数,如果月份到达了13,那就让他变为1,年份 。

注: 这里写的GetMonthDay还去要判断是否是闰年,所以我们传参还需要传年份。

        由于这个函数经常用到,我们直接到类内定义作为对象的内联函数。

        传入的参数可能是一个负数,所以我们还需要考虑负数的情况。

代码:

代码语言:javascript复制
int GetMonthDay(int year, int month)
{
	static int montharr[13] = { 0,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 montharr[month];
	}
}
Date& Date::operator =(const int day)
{
	if (day < 0)
	{
		return  *this -= abs(day);
	}
	_day  = day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month  ;
		if (_month == 13)
		{
			  _year;
			_month -= 12;
		}

	}
	return *this;
}

 分析:这里返回值类型为 Date& 的原因是返回的时候会生成一个返回值的拷贝,用一个引用的话能减少一次拷贝。有返回值的原因是为了能够链式调用,也就是能够连续使用。

5、重载 号

号与 = 号唯一的区别在于, 号返回的是还没变之前的数据。所以就需要在函数里面创建一个临时变量来存储变化之前的数据。我们只需要复用 = 就行了。

代码:

代码语言:javascript复制
Date Date::operator (const int day) const
{
	Date ret(*this);
	ret  = day;
	return ret;
}

6、重载  -= 号

思路和 = 的重载很相似。我们需要先用日减去需要 -= 的天数,如果 _day <= 0。那么先

_month--  ,然后 _day 加上当月的天数即可。如果 _month == 0,那么我们需要 _year-- ,然后将  _month 重置为12。

注:传入的参数可能是一个负数,所以我们还需要考虑负数的情况。

代码:

代码语言:javascript复制
Date& Date::operator-=(const int day)
{
	if (day < 0)
	{
		return *this  = abs(day);
	}
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day  = GetMonthDay(_year, _month);
	}
	return *this;
}

7、重载 - 号

和 号的思路一样。

代码:

代码语言:javascript复制
Date Date::operator-(const int day) const
{
	Date ret(*this);
	ret -= day;

	return ret;
}

8、前置 和后置 的重载

前置 :返回 =1后的 this指针 即可。

代码:

代码语言:javascript复制
Date& Date::operator  ()
{
	*this  = 1;
	return *this;
}

由于返回后 this 指针还是存在的,所以我们可以返回Date类型的引用来减少一次拷贝。

后置 :由于无法区分前置和后置,所以在函数的参数中加了一个 int 类型来区分。

后置 要返回未变化之前的数据,所以我们还得创建一个变量来记录。

代码:

代码语言:javascript复制
Date Date::operator  (int)
{
	Date ret(*this);
	*this  = 1;

	return ret;
}

分析:通过这两段代码我们就能够知道,前置 的性能要由于后置 ,原因就是能够少创建一个临时的变量,返回的时候返回引用也减少了一次拷贝。

9、前置--和后置--的重载

这个和 的思路是一致的,我们看下面的代码:

代码语言:javascript复制
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
Date Date::operator--(int)
{
	Date ret(*this);
	*this -= 1;

	return ret;
}

10、- 号的再次重载:两个日期类相减

我们知道,两个日期类相减,得到的其实就是他们之间相差的天数。因此这个函数的返回值也就是int类型了。

思路:我们应该先来判断一下是前面的大还是后面的大,然后如果是后面的大,那我们最后的结果就应该乘上一个-1,这里我们用 flag 来代替。当小的那个对象 到大的对象一样大的时候, 的次数就是中间差的天数的。

代码语言:javascript复制
int Date::operator-(const Date& d) const
{
	Date max = *this;
	Date min = d;
	int flag = 1;

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

	int ret = 0;
	while (min != max)
	{
		  min;
		ret  ;
	}
	return ret * flag;
}

11、 << 和 >> 号的重载。

当我们创建一个名叫d1的变量时,cout << d1  是不可以的,因为编译器不知道该怎么做。

那么就要我们来重载 << 号。

其实,cout和cin也是类的对象的一种,cout也就是ostream类的一个对象。

所以函数括号内的一个参数就是osteam&类型的了,我们命名out。但是我们知道,如果这个函数是在Date类内的,那么函数的第一个参数就会是this指针,那么到时候的输出的指令就应该是

d1 << cout 那这样和我们的预期就颠倒了,所以我们需要在 Date 类外来定义。这样就可以做到Date类型的参数为第二个了。

代码:

代码语言:javascript复制
inline ostream& operator<<(ostream& out, Date & d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}

分析:增加内联的原因是这段代码比较短,并且会频繁调用。

           返回值为 ostream& 使得可以链式调用。

>> 号和 << 号的思路一样,代码如下:

代码语言:javascript复制
inline istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}
  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型 ,不能改变其含义
  4. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  5. .*   ::   sizeof   ?:   . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

全篇代码

Date.h

代码语言:javascript复制
#pragma once
#include <iostream>
using namespace std;

class Date
{
	friend ostream& operator<<(ostream& out, Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	Date(const int year = 1, const int month = 1, const int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	int GetMonthDay(int year, int month)
	{
		static int montharr[13] = { 0,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 montharr[month];
		}
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

	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 =(const int day);
	Date operator (const int day) const;
	Date& operator-=(const int day);
	Date operator-(const int day) const;
	Date& operator  ();
	Date operator  (int);
	Date& operator--();
	Date operator--(int);

	//两个日期相减
	int operator-(const Date& d) const;
private:
	int _year;
	int _month;
	int _day;
};

inline ostream& operator<<(ostream& out, Date & d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}

inline istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

Date.cpp

代码语言:javascript复制
#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"
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 (_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 =(const int day)
{
	if (day < 0)
	{
		return  *this -= abs(day);
	}
	_day  = day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month  ;
		if (_month == 13)
		{
			  _year;
			_month -= 12;
		}

	}
	return *this;
}

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

Date& Date::operator-=(const int day)
{
	if (day < 0)
	{
		return *this  = abs(day);
	}
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day  = GetMonthDay(_year, _month);
	}
	return *this;
}

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

	return ret;
}

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

Date Date::operator  (int)
{
	Date ret(*this);
	*this  = 1;

	return ret;
}

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

	return ret;
}

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

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

	int ret = 0;
	while (min != max)
	{
		  min;
		ret  ;
	}
	return ret * flag;
}

0 人点赞