c++(日期类)

本章主要以日期类为例,练习重载各种运算符,需要重点掌握:

1、日期类的<、 <=、 ==、>、 >=、 !=、重载

2、日期类的 +、 +=、-、-=、++、--、重载

3、日期类 - 日期类

4、日期类的 << 、>>重载

5、权限问题


目录

1、运算符<、 <=、 ==、>、 >=、 !=、重载

1.1运算符<重载

1.2 == 运算符重载 

1.3 <= 运算符重载 

 1.4 >运算符重载

 1.5>=运算符重载

 2、日期类的 +、 +=、-、-=、++、--、重载

2.1+=运算符重载

 2.1+运算符重载

  2.3-=运算符重载

2.4-运算符重载 

2.5--运算符重载

2.5.1前置--

2.5.2后置-- 

2.6++运算符重载  

 2.6.1前置++

2.6.2后置++ 

3、日期类-日期类 

4、<<  >>运算符重载 

4.1<<流提取 

4.2>>运算符重载 

 5、权限问题



我们按照文件分类,将声明和定义分开,方便程序阅读,移植。

1、运算符<、 <=、 ==、>、 >=、 !=、重载

在完成各重载函数之前,我们需要将日期类在头文件中定义完整, 构造函数,拷贝构造函数,等需要构造的,需要注意的是,对于默认成员函数,由于是日期类,并没有申请资源的操作,所其他的我使用的是默认的。代码如下所示:

class Date
{
     //友元函数进行声明,方便在外面调用类成员
	friend ostream& operator << (ostream& out, const Date& d);
	friend istream& operator >> (istream& in,  Date& d);
public:
	//构造函数
	Date(int year = 1, int month = 1, int day = 1);//类的成员函数一般默认为内联函数

	//显示函数 比较短放在一起
	void Print() const
	{
		cout << _year << "--" << _month << "--" << _day << endl;
	}
	//拷贝构造函数
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	//运算符重载
	bool operator<(const Date& x)const;
	bool operator==(const Date& x)const;
	bool operator<=(const Date& x)const;
	bool operator>(const Date& x)const;
	bool operator>=(const Date& x)const;
	bool operator!=(const Date& x)const;
	//得到某个月份的天数
	int GetMonthDay(int year, int month);

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

};
ostream& operator << (ostream& out, const Date& d);
istream& operator >> (istream& in, Date& d);

 对于初始化函数,我们需要给定初值,并对初值进行合理判断,代码如下:

//构造函数
  Date::Date(int year, int month, int day)
 {
	  if (month > 0 && month < 13
		  && day > 0 && day <= GetMonthDay(year, month))
	  {
		_year = year;
		_month = month;
		_day = day;
	  }
	  else
	  {
		  cout << "非法日期" << endl;
		  assert(false);
	  }
 }

1.1运算符<重载

 我们需要完成日期类的  <重载 具体的含义是希望实现日期类实例化对象之间的比较,分析一下,我们在比较内置成员变量的时候,我们是通过bool值确定,两个变量的大小,对象其实就是集成了,成员变量的大小。具体代码如下:

  //<运算符重载
  bool Date:: operator<(const Date& x) const
  {
	  if (_year < x._year)
	  {
		  return true;
	  }
	  else if (_year == x._year && _month < x._month)
	  {
		  return true;
	  }
	  else if (_year == x._year && _month == x._month && _day < x._day)
	  {
		  return true;
	  }
	  else
		  return false;
  }

1.2 == 运算符重载 

  //==运算符重载
  bool Date:: operator==(const Date& x) const
  {
	  if (_year == x._year && _month == x._month && _day == x._day)
	  {
		  return true;
	  }
	  return false;
  }

1.3 <= 运算符重载 

小于或者等于都满足条件,我们可以把上面两个运算符重载集成一下就成了 <=运算符重载,代码如下:

 

  //<=运算符重载
  bool Date:: operator<=(const Date& x) const
  {
	  return *this < x || *this == x;
  }

 1.4 >运算符重载

把<=取反就是> 

 //>运算符重载
  bool Date:: operator>(const Date& x) const
  {
	  return !( * this <= x);
  }

 1.5>=运算符重载

  //>=运算符重载
  bool Date:: operator>=(const Date& x) const
  {
	  return !(*this < x);
  }

1.6!=运算符重载

  //!=运算符重载
  bool Date:: operator!=(const Date& x) const
  {
	  return !(*this == x);
  }

 完成这些运算符重载,我们写个函数测试一下,代码如下

void TestDate9()
{
	Date d1(2023, 5, 5);
	d1.Print();

	const Date d2(2023, 5, 9);
	d2.Print();

;

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

}

运行结果如下:

 2、日期类的 +、 +=、-、-=、++、--、重载

 对于日期类,我们可能期望 看到 在当前日期的基础上往后推移多少天,或者往前倒退多少天的日子,这个时候就产生了 +=、-=的运算符重载,当我们不希望当前日期被改变的时候,也就出现了 + 、-运算符重载,当然步长为1天的话,那就是++、--运算符重载。

我们要实现这些运算符重载,都得知道当前年份的月份天数,为了方便,我们写一个获取天数的函数,调用就行,具体代码如下:

 int Date::GetMonthDay(int year, int month)
  {
//设置成静态的话,每次进来就不会再开辟定义
	  static int monthday[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;
	  }
	  return monthday[month];
  }

2.1+=运算符重载

返回加完之后的天数,这里需要注意的是,在循环体内,应该先减去当月的天数,再进行月操作,,具体代码如下:

  //日期类 +=天数
 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;
  }

 2.1+运算符重载

不改变当前日期,所以我们需要定义一个对象,保存当前日期的值,然后对拷贝的对象进行操作,然后将值返回,因为是值返回,所以函数返回类型用Date,具体代码如下:

 //日期类 +天数
 Date Date::operator+(int day) const
 {
	 //拷贝一个对象,对拷贝的对象进行操作
	 Date temp(*this);

	 temp += day;

	 return temp;
 }

  2.3-=运算符重载

 //日期类 -=天数
 Date& Date::operator-=(int day)
 {
	 if (day < 0)
	 {
		 return *this += -day;
	 }
	 //减去天数
	 _day -= day;
	 //判断天数
	 while (_day <= 0)
	 {

		
		 --_month;
		 if (_month == 0)
		 {
			 _month = 12;
			 --_year;
		 }
		 _day += GetMonthDay(_year, _month);

	 }
	 return *this;
 }

2.4-运算符重载 

 Date Date::operator-(int day) const
 {
	 //拷贝一个对象,对拷贝的对象进行操作
	 Date temp(*this);

	 temp -= day;

	 return temp;
 }

2.5--运算符重载

需要注意的是,对于--的运算符,有前置--和后置--我在类和对象(中)介绍过前置和后置如何在重载时候区分的 这里我就不再赘述。

2.5.1前置--

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

2.5.2后置-- 

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

2.6++运算符重载  

 2.6.1前置++

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

2.6.2后置++ 

 

 //后置++

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

写完这些函数,我们测试一下 具体代码如下

void TestDate9()
{
	Date d1(2023, 5, 5);
	d1.Print();
	d1 -= 100;
	d1.Print();
	d1 - 100;
	d1.Print();
	d1 += 100;
	d1.Print();
	d1 + 100;
	d1.Print();
	d1--;
	d1.Print();
	d1++;
	d1.Print();
	--d1;
	d1.Print();
	++d1;
	d1.Print();


}

运行结果如下:

3、日期类-日期类 

当我们想获取两个日期之间的天数的时候,就得用到-重载, 我们可以利用判断两个日期谁大谁小,然后利用小的日期累加,直到加的跟大日期一样,中间类加的次数,就是天数。具体代码如下:

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

	 if (*this < d)
	 {
		 max = d;
		 min = *this;
		 flag = -1;
	 }
	 int count = 0;
	 while (min != max)
	 {
		 ++count;
		 ++min;

	 }
	 return flag * count;
 }

 调用测试一下 代码如下:

void TestDate6()
{
	Date d1(2023, 5, 5);
	Date d2(1949, 10, 1);

	cout << d1 - d2 << endl;
	cout << d2 - d1 << endl;
}

 运行结果如下:

4、<<  >>运算符重载 

 我们之前在只有内置成员的时候,使用cout cin 不用特地像c语言使用的 scanf和printf那样,需要指定 类型,这是为什么呢,因为c++库函数中 将<< >>重载了,能够识别不同类型也是因为函数重载,如下图所示:

那对于日期类的 流插入,流提取,该如何实现呢? 

4.1<<流提取 

对于流提取,他没法写成成员函数,因为成员函数有隐藏指针*this 而且是const类型,这就导致了其不可被修改,那我们是不能往里写东西的,这时候,我们就要写在类之外了,写在类之外,该如何访问类成员变量呢?我们可以使用友元声明一下,让其可以被访问,声明如下:

 

 对于流提取还需要注意的是,当我们连续提取的时候,是从左往右执行的,我们完成一个提取,要将流返回,以供读取下一个成员具体代码如下:

 //重载 流插入
 ostream& operator << (ostream& out, const Date& d)
 {
	 //c++支持 对内置类型的重载
	 //不同变量类型,是因为函数重载
	 out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	 return out;
 }

4.2>>运算符重载 

 

 // 重载 流提取
 istream& operator >> (istream& in, Date& d)
 {
	 int year, month, day;
	 in >> year >> month >> day;
	 if (month > 0 && month < 13 && day >0 && day <= d.GetMonthDay(year, month))
	 {
		 d._year = year;
		 d._month = month;
		 d._day = day;
	 }
	 else
	 {
		 cout << "非法日期" << endl;
		 assert(false);
	 }
	 return in;
 }

写完之后进行测试,测试代码如下:

void TestDate7()
{
	Date d1(2023, 5, 5);
	d1 += 100;

	// 流插入
	cout << d1; // operator<<(cout, d1);


	Date d2(2023, 5, 5);
	Date d3(1949, 10, 1);

	//d1 = d2 = d3;

	cout << d2 << d3 << d1;

	cin >> d1 >> d2;
	cout << d2 << d1;

	//Date d4(2023, 13, 1);
	//cout << d4;
}

运行结果如下:

 5、权限问题

我们之前说过,形参*this是const类型的 是不可以被修改的,如果我们在类实例化的时候,使用 cosnt Dae d 创建的对象,就会涉及到权限放大,将不可被修改的对象成员,赋值给可以被修改的变量,为了避免这样的问题,祖师爷涉及了一种方法,就是不会被修改的函数,我们都在后面加 const 这样,只会存在权限平移和权限缩小 不会存在权限放大,这就是为什么在头文件中会看到有的函数后面跟了const 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值