【运算符重载】日期类实战篇

2023-11-09

一、任务清单


  • 两个日期对象的大小比较:< 、 >、 =、 ==、 >=、 <=
  • 日期对象加减天数:++(前置和后置) 、–(前置和后置)、 +=、 -=、+、 -
  • 两个日期对象之间相隔天数:-
  • 流提取与流插入的重载

二、基本原则


  • ① 采用传值返回一定是对的,就是需要拷贝增加额外开销。能不能用使引用返回取决于出函数后引用的对象还在不在
  • ② 尽可能的实现各个函数之间的复用
  • ③ 长度较短的函数推荐使用内联函数的形式。注意内联函数的定义与声明不能分离,否则在编译的时候内联函数不会加入到符号表中产生链接错误。所以最好还是写入到类中,因为类中的函数默认是内联的,同时可以轻松访问成员变量
  • ④ 在复用函数的时候,应该尽可能减少拷贝的次数来提高效率

三、功能实现


① 构造函数

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{}

private:
	int _year;
	int _month;
	int _day;
};

②两个对象间比大小

 我们只实现 > 和 == 的重载,其他的都可以以此来复用(没有特殊说明都是写在类里面的,为了减少篇幅,类就不写出来了)

bool operator== (const Date& d) const
{
	return _year == d._year && _month == d._month && _day == d._day;
}


bool operator> (const Date& d) const
{
	if (_year > d._year ||
		_year == d._year && _month > d._month ||
		_year == d._year && _month == d._month && _day > d._day) 
		return true;
	else
		return false;
}

【评注】

  • ① 使用引用传值来减少拷贝,最好加上const保护
  • ② 对象的成员变量不需要修改时,最好给this指针加上 const 保护,这样通对象和const对象都可以调用该成员函数 参考文章
bool operator>= (const Date& d) const
{
	return operator>(d) || operator==(d);
}

bool operator< (const Date& d) const
{
	return !operator>=(d);
}

bool operator <= (const Date& d) const
{
	return !operator>(d);
}

③ 日期对象加减天数

1.加减运算符的重载
int Getmonthday(int year, int month) const // 之后反复用到,不再赘述
{
	static int day[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 day[month];
}


Date operator+ (const int day) const
{
	Date tmp(*this);  // 首先进行拷贝构造
	tmp._day += day;
	while (tmp._day > Getmonthday(tmp._year, tmp._month))
	{
		tmp._day -= Getmonthday(tmp._year, tmp._month);
		tmp._month++;
		if (tmp._month == 13)
		{
			tmp._month = 1;
			tmp._year++;
		}
	}
	return tmp;
}
Date operator- (const int day) const
{
	Date tmp(*this);
	if (day < 0)
	{
		tmp = tmp + (-day);
		return tmp;
	}
	tmp._day -= day;
	while (tmp._day < 0)
	{
		tmp._month--;
		if (tmp._month == 0)
		{
			tmp._month = 12;
			tmp._year--;
		}
		tmp._day += Getmonthday(tmp._year, tmp._month);
	}
	return tmp;
}

【评注】

  • 进行加减运算时,本身是不变的,所以需要先拷贝临时对象,最后将临时对象返回
  • 因为临时对象出作用域后会被销毁,所以不能采用引用返回
  • 上述代码各发生两次拷贝——创建临时变量、返回临时对象
2.+= -= 运算符的重载
Date& operator+= (const int day)
{
	_day += day;
	while (_day > Getmonthday(_year, _month))
	{
		_day -= Getmonthday(_year, _month);
		_month++;
		if (_month == 13)
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}

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

【评注】

  • 基本思想与±的实现是非常相似的
  • 区别在于+=、-=对象本身是会改变的,所以不需要额外的拷贝,直接在原对象上操作
  • 出函数后原对象并没有被销毁,所以可以使用引用返回减少拷贝
  • +=、 -=的实现过程中没有用到拷贝构造
3.± 与+= -=之间的复用
// +复用+=
Date operator+ (int day)
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}

// +=复用+
Date& operator += (int day)
{
	*this = *this + day;
	return *this;
}

根据上面代码的比较我们可以得出以下结论:

  • +复用+=的时候,+的重载需要拷贝2次,而+=的重载本身不需要拷贝
  • +=复用+的时候,+的重载需要拷贝2次,而+=的重载也需要拷贝两次
  • 所以综上+复用+=的效果最佳
4.前置++与后置加加
// 前置减减后置减减同理,就不再这里赘述了
Date& operator++ ()    // 前置加加
{
	*this += 1;
	return *this;
}

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

【评注】

  • 为了区别前置加加和后置加加,规定后置加加带一个int型参数,前置加加不带参。注意带的参数类型必须是int类型,形参名可写可不写。
  • 前置加加先加加后使用,所以将自增后的对象本身返回;后置加加先使用后加加,所以将自增前的对象本身返回

④两个对象之间的日期差

int operator- (const Date& d) const
{
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		max = d;
		min = *this;
	}
	int cnt = 0;
	while (max != min)
	{
		min++;
		cnt++;
	}
	return cnt;
}

【评注】

  • 计算两个天数差的方法有很多,这是最简单的方法
  • 还可以计算两个到同一天的时间然后作差 + 1

⑤流插入与流提取运算符的重载

【问题一】为什么C++中的 cin 和 cout 会自动识别类型?
【答】因为流提取运算符和流插入运算符将所有常见的内置类型都给重载了
image-20220707083514762


【问题二】cout 和 cin 是什么?
【答】cout 是 ostream 的全局对象;cin 是 istream 的全局对象
image-20220707083903909


【问题三】流插入运算符和流提取运算符的重载可以写在类里面吗?
【答】不可以。因为类里面的函数第一次参数默认为 this 指针,所以在使用的时候不是 cout << xxx,而变成了xxx << cout
在这里插入图片描述


【问题四】写在函数外面如何访问成员变量
【答】使用友元函数,注意在类里面声明的时候前面需要加上 const,但是在定义的时候不需要加上 const。image-20220707085311574
image-20220707085709605
友元函数的特性:

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数,因此也没有this指针
  • 友元函数不能用const修饰(因为没有this指针)
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制

【问题五】定义与声明分离的时候
【答】要在头文件声明,源文件定义,否则会出现链接错误。而类里面定义的函数默认是内联的,不会添加到符号表中,就不会出现问题。类里面长的函数也具有这样内联的属性

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【运算符重载】日期类实战篇 的相关文章

随机推荐

  • 非常详细的Django使用Token(转)

    基于Token的身份验证 在实现登录功能的时候 正常的B S应用都会使用cookie session的方式来做身份验证 后台直接向cookie中写数据 但是由于移动端的存在 移动端是没有cookie机制的 所以使用token可以实现移动端和
  • C#添加配置文档基础

    程序编译后在日常使用中是无法更改固定参数的 如果需要更改里面的参数每次都要改动源代码这将变得非常麻烦 所以我们可以使用到配置文档 这里将介绍配置文档最基础的使用方法 1 新建一个App config文件 在项目中新建一个App config
  • DETR系列大盘点

    点击下方卡片 关注 自动驾驶之心 公众号 ADAS巨卷干货 即可获取 点击进入 自动驾驶之心 目标检测 技术交流群 后台回复 2D检测综述 获取鱼眼检测 实时检测 通用2D检测等近5年内所有综述 自从VIT横空出世以来 Transforme
  • cookie设置为关闭浏览器后清除,打开后cookie还是没有清除

    今天踩了几个cookie的坑 花了我2小时 问题是这样的 我给aaa域名下的a html页面设置了一条很简单的cookie document cookie name abc 这样设置后默认为关闭浏览器后清除该cookie 可是关闭后打开co
  • vue elementUI 之 this.$confirm 的使用

    当进行一些操作时 有时需要弹出一些确定信息 一般有两种形式 提示框和确认框 通常为一个确定动操作 一个取消操作 如下 this confirm 您确定删除吗 提示 confirmButtonText 确定 cancelButtonText
  • Windows 系统下常用的八个网络配置命令

    一 ipconfig ipconfig 是 Windows 网络中最常使用的命令 用于显示计算机中网络适配器的 IP 地址 子网掩码及默认网关等信息 命令基本格式 ipconfig all renew adapter release ada
  • Modbus RTU简介(上)

    1 前言 1 1 什麽是Modbus Modbus是一种用于工业控制的标准通信协议 它定义了装置之间在应用层的消息封装模式 沟通方法 沟通顺序 Modbus的优势 Modbus协议是开源免费的 Modbus支援多种常见工控接口 RS232
  • 服务器里修改登录密码,云服务器修改登录密码

    云服务器修改登录密码 内容精选 换一换 如果密码丢失 或创建时未设置密码 推荐您在控制台设置登录密码 如果密码丢失 或创建时未设置密码 推荐您在控制台设置登录密码 云服务器修改登录密码 相关内容 当云服务器密码即将过期 密码泄露或首次登录时
  • #关于pytorch和torchvision对应版本#

    pytorch和torchvision对应版本记录 进入pytorch官网查看历史版本 有对应信息pytorch历史版本 比如pytorch1 5 1对应torchvision0 6 1 CUDA 9 2 conda install pyt
  • LVGL v7 使用心得及工具分享

    1 v7与v8的区别 对于v7来说 并没有v8优化的那么全面和完善 有些好用的功能在v7中也并未实现 但这并不代表v7就不好 在稳定性和兼容性这方面v7做的比v8好很多 虽然现在大多数都能上v8 其次v7与v8是两个大版本变动 很多API都
  • SQLServer与MySQL的一些常用操作加字段、修改字段、重置自增ID

    SQLServer与MySQL的一些常用操作 总结一些SQLServer与MySQL的一些常用操作 添加字段 修改字段 重置自增ID 添加字段 SQLServer 在SQLServer中 我们可以使用ALTER TABLE命令来添加表字段
  • UE4 禁用引擎Runtime模式下的引擎内置按键

    本文内容主要讲解在开发过程中 不想用引擎自带的按键如何禁用它 这些按键类似于一个快捷键工具例如F1 F5之类的按键 但最终打包成发行版的项目会自动禁用这些按键 所以不用担心用户会误触这些按键 1 找到引擎目录下的BaseInput ini文
  • sql中的coalesce函数

    COALESCE函数是一个SQL中的标准函数 它用于返回多个表达式中的第一个非NULL值 它的通常用途是在查询中提供默认值以避免NULL值 COALESCE函数的语法如下 COALESCE expression1 expression2 e
  • Elementui的select怎么获取选中的对象

    今天在开发中碰到了这样一个问题 平常使用select只是获取到他的值就可以了 突然需要获取选中的对象 倒是一下有些无从下手 也看了一些别人的文章 基本都没有很清晰的指出方法 我在这里做一个备注
  • 网站服务器速度快取决于,建站经验 网站打开速度快慢的因素

    判断一个网站打开速度快或者是慢主要取决于以下一些因素 一 网页内容的大小 网页内容所包括的文本 产品的图片 静态的 动态的 视频 flash文件等 这里涉及到浏览器的原理 浏览器的技术原理就是将网页下载到客户本地缓存 然后通过浏览器解析源码
  • 网易2018校园招聘编程题真题集合 (部分)

    第一题 小易准备去魔法王国采购魔法神器 购买魔法神器需要使用魔法币 但是小易现在一枚魔法币都没有 但是小易有两台魔法机器可以通过投入x x可以为0 个魔法币产生更多的魔法币 魔法机器1 如果投入x个魔法币 魔法机器会将其变为2x 1个魔法币
  • hive报metadata.HiveException: Hive Runtime Error while processing row (tag=0)错误

    今天跑一条统计的SQL出现Caused by org apache hadoop hive ql metadata HiveException Hive Runtime Error while processing row tag 0 ke
  • android -------- AES加密解密算法

    AES加密标准又称为高级加密标准Rijndael加密法 是美国国家标准技术研究所NIST旨在取代DES的21世纪的加密标准 AES的基本要求是 采用对称分组密码体制 密钥长度可以为128 192或256位 分组长度128位 算法应易在各种硬
  • HTML5边玩边学(8):俄罗斯方块就是这么简单 之 数据模型篇

    HTML5边玩边学 8 俄罗斯方块就是这么简单 之 数据模型篇 特别提示 本文中的运行效果需要 Chrome 浏览器或者 Firefox 浏览器 一 从数据出发还是从界面出发 要写一个俄罗斯方块小游戏 我们先来一块考虑一下下面几个问题 1
  • 【运算符重载】日期类实战篇

    学习导航 一 任务清单 二 基本原则 三 功能实现 构造函数 两个对象间比大小 日期对象加减天数 1 加减运算符的重载 2 运算符的重载 3 与 之间的复用 4 前置 与后置加加 两个对象之间的日期差 流插入与流提取运算符的重载 一 任务清