c++(日期类)

news2025/1/12 21:10:12

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

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 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/501906.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DOM事件(下)

事件执行机制 ●今天来聊一聊事件的执行机制 ●什么是事件的执行机制呢&#xff1f; ○思考一个问题&#xff1f; ○当一个大盒子嵌套一个小盒子的时候&#xff0c;并且两个盒子都有点击事件 ○你点击里面的小盒子&#xff0c;外面的大盒子上的点击事件要不要执行 事件的传播&…

ASEMI代理ADM706SARZ-REEL原装ADI车规级ADM706SARZ-REEL

编辑&#xff1a;ll ASEMI代理ADM706SARZ-REEL原装ADI车规级ADM706SARZ-REEL 型号&#xff1a;ADM706SARZ-REEL 品牌&#xff1a;ADI /亚德诺 封装&#xff1a;SOIC-8 批号&#xff1a;2023 安装类型&#xff1a;表面贴装型 引脚数量&#xff1a;8 工作温度:-40C~85C …

JavaWeb《后端内容:2. MVC-IOC-ServletContext-事务管理-过滤器Filter》

1. 准备和回顾 本篇基于上一篇JavaWeb《后端内容&#xff1a;1. Tomcat - Servlet - Thymeleaf》 继续使用mvc进行优化&#xff0c;复制上面模块的代码&#xff0c;并新建工件和项目和配置服务器 这里可以再好好复习揣摩一下这里index页面的逻辑部分&#xff0c;尤其是关键字的…

PostgreSQL类型系统——Data Types

PostgreSQL Data Types PostgreSQL has a rich set of native data types available to users. Users can add new types to PostgreSQL using the CREATE TYPE command. PostgreSQL有一组丰富的本地数据类型可供用户使用。用户可以使用CREATE TYPE命令向PostgreSQL添加新类型…

[Gitops--12]微服务项目发布

微服务项目发布 1. 微服务项目发布 [流水线] [创建] [下一步] [创建] 1.1 mall-gateway 确认项目中的路由配置都正确 mall-gateway/src/main/resources/application.yml如果不一样就批量替换一下,一共7处 1.2 mall-auth-server mall-auth-server1.3 mall-cart 1.4 mall-c…

ChatGLM-LLaMA-chinese-insturct 学习记录(含LoRA的源码理解)

ChatGLM-LLaMA-chinese-insturct 前言一、实验记录1.1 环境配置1.2 代码理解1.2.1 LoRA 1.4 实验结果 二、总结 前言 介绍&#xff1a;探索中文instruct数据在ChatGLM, LLaMA等LLM上微调表现&#xff0c;结合PEFT等方法降低资源需求。 Github: https://github.com/27182812/Ch…

Win10任务栏透明,3个超好用解决方法!

案例&#xff1a;win10任务栏透明怎么办&#xff1f; 【我的电脑不知道为什么任务栏突然就变透明了&#xff0c;现在不知道该如何解决&#xff0c;遇到这种情况应该怎么办呀&#xff1f;】 Win10任务栏是Windows 10操作系统的一部分&#xff0c;通常默认为不透明。然而&#…

asp.net+sqlserver企业公司进销存管理系统

基于WEB的进销存管理系统主要企业内部提供服务&#xff0c;系统分为管理员&#xff0c;和员工2部分。 在本基于WEB的进销存管理系统中分为管理员&#xff0c;和普通用户2中模式&#xff0c;其中管理人员主要是对企业内商品类型。商品信息商品的出入库信息&#xff0c;以及员工…

堆栈溢出一般是什么原因?

堆栈是一个在计算机科学中经常使用的抽象数据类型。堆栈中的物体具有一个特性&#xff1a; 最后一个放入堆栈中的物体总是被最先拿出来&#xff0c; 这个特性通常称为后进先出(LIFO)队列。 堆栈中定义了一些操作。 两个最重要的是PUSH和POP。 PUSH操作在堆栈的顶部加入一 个元素…

MySQL深度分页

1. 什么是深度分页 深度分页问题的本质是在 MySQL 数据库中&#xff0c;通过 LIMIT 和 OFFSET 关键字进行分页时&#xff0c;MySQL 需要在每次查询时扫描整张表&#xff0c;直到找到当前页的数据。这种查询方式需要进行大量的磁盘 I/O 和内存操作&#xff0c;导致查询效率非常…

Microsoft Edge新功能测评体验

Microsoft Edge使用体验 Microsoft Edge是一款现代化的浏览器&#xff0c;它拥有众多功能和强大的性能&#xff0c;为用户带来更加流畅的浏览体验。 Edge最近推出了分屏功能&#xff0c;支持一个窗口同时显示两个选项卡&#xff0c;这可以大大提高生产力和多任务处理能力。 一…

什么样的蓝牙耳机佩戴舒适?蓝牙耳机佩戴舒适度排名

越来越多的人开始使用运动蓝牙耳机了&#xff0c;不仅仅是因为蓝牙耳机的它无耳机线的束缚&#xff0c;日常还很便携&#xff0c;市面上的蓝牙耳机质量参差不齐&#xff0c;有些佩戴舒适度也比较差&#xff0c;下面整理了几款评分还不错的几款蓝牙耳机。 一、南卡小音舱Lite2蓝…

第四十四章 Unity 滑动条 (Slider) UI

本章节我们介绍滑动条 (Slider)&#xff0c;它允许用户通过拖动鼠标从预定范围中选择数值。首先&#xff0c;我们点击菜单栏“GameObject”->“UI”->“Slider”&#xff0c;调整其位置&#xff0c;最终效果如下 我们发现滑动条 (Slider)下面有三个子游戏对象Background&…

如何使DocuWare成为所有部门的数据中心

如何使DocuWare成为所有部门的数据中心 自动化流程通常需要多个部门的数据&#xff0c;而各个部门通常使用不同的软件。 DocuWare可帮助您集中管理所有信息&#xff0c;并将信息应用于您的进程和工作流程当中。 您的公司使用不同的系统&#xff0c;但您又想将这些数据整合在一…

手敲Mybatis(十)-完善ORM框架支持增删改查

我们把基本的功能都完成了&#xff0c;解析xml、构建映射代理、执行sql&#xff0c;解析处理结果&#xff0c;目前这些只支持查询&#xff0c;我们还差添加下增删改的功能&#xff0c;本章节就来完善下增删改&#xff0c;其实本章节比较简单&#xff0c;因为之前的每个章节都已…

这一篇LiveData掉不掉价(使用->原理分析->粘性事件解决)

1. 简介 LiveData 是一种可观察的数据存储器类。与常规的可观察类不同&#xff0c;LiveData 具有生命周期感知能力&#xff0c;意指它遵循其他应用组件&#xff08;如 activity、fragment 或 service&#xff09;的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周…

数据备份系列:Rsync 备份详解(二)

一、Rsync Cron 场景使用 在对数据备份要求实时性不高的情况下&#xff0c;可优先考虑该场景&#xff0c;选择一个合适的时间&#xff0c;对数据进行定时远程增量同步。 在《数据备份系列&#xff1a;Rsync 备份详解&#xff08;一&#xff09;》中我们已经对服务搭建以及远程…

【虚幻引擎】UE5数据表格导入

数据表 顾名思义&#xff0c;DataTable是一种表格&#xff0c;里面装着大量游戏相关的数据&#xff0c;这些数据会按照其含义和用途分类&#xff0c; 其中&#xff0c;数据字段可以是UObject的任意有效属性&#xff08;包括资产的引用信息&#xff09;。设计师若要将 CSV文件导…

c++类的静态变量、静态函数 笔记

正文&#xff1a; 1、看下面这个是一个常规的类 #include <iostream> #include <windows.h> using namespace std; class BOX{int callsNum1;public:BOX(){callsNum;};int fun(){return callsNum;}; }; // int BOX::callsNum1;// 程序的主函数 int main() {SetCo…

【某区护网】从外网打点到拿下域控

目录 web打点 反弹shell与权限维持 主机信息收集与反向代理 攻击域控 前端时间刚结束了攻防演练活动&#xff0c;其中一项成果为拿下某集团域控制器权限&#xff0c;直接控制域内主机5000多台。以下为攻击过程的粗略记录&#xff0c;整体来说还是比较容易。 web打点 接到…