【C++】类和对象——流插入和流提取运算符重载

news2024/12/28 4:30:43

目录

  • 前言
  • ostream和istream
  • 自定义类型的流插入重载
  • 自定义类型的流提取重载
  • 解决私有问题
  • 日期类总接口

请添加图片描述

前言

  我们在上一节实现日期类时,在输入和输出打印时,经常会调用两个函数:

void Insert()//输入函数
	{
		cin >> _year;
		cin >> _month;
		cin >> _day;
		if (!CheakDay())
			cout << "输入错误,请重新输入" << endl;
	}
void Print()//输出函数
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}

  我们经常调用这两个函数进行输入输出日期,我会觉得麻烦,那我可不可以直接使用cout和cin来输出输入呢,这就用到我们流插入和流提取运算符的重载。

ostream和istream

  在cplusplus网站中,就有详细介绍:
在这里插入图片描述
其实,cout是ostream类型的全局对象,cin是一个istream类型的全局对象。这些都是在C++的标准库中写好了,它们被包含在iostream这个头文件里面。
  ostream和istream里面都写了很多函数,想要输入或者输出带精度的都可以进行调用。
  我们都知道,我们可以直接调用cout来输出内置类型,是因为它已经在库中写好了重载函数,如下图所示:
在这里插入图片描述

例如:
int i=1;
cout<<i ——》等价于cout.operator<<(i)
double d=1.1
cout<<d ——》等价于cout.operator<<(d)
cout能自动识别类型,本质上是因为这些流插入重载自动构成函数重载。
cin也一样。

  当我们想要cout一个自定义类型,即cout<<d1,发现代码会报错,因为库里面没有对应写自定义类型的输出,我们要自己重载写一个。

自定义类型的流插入重载

  虽然上图中函数的参数只有一个,但我们要知道的是operator<<是写在ostream这个类里面的,所以这个函数应该是有两个参数,一个是隐藏的this指针,所以实际上库里声明定义的重载应该为:

ostream& operator<<(ostream& this, int val);

  当我们仿照其写自定义类型的流插入重载函数时,ostream& this,这个参数是不能省略的。
  明白了这个,现在我们在日期类中类中声明流插入重载函数:

void operator<<(ostream& out);
//必须用引用传参是因为ostream类型不支持拷贝构造
//(传参时如果传的自定义类型会调用它的拷贝构造)

  在类外定义这个函数时:

void Date::operator<<(ostream& out)
{
    out << _year << "年" << _month << "月" << _day << "日" << endl;
}

  我们重载的是自定义类型,但自定义类型内部最终还是内置类型。

out << _year << “年” << _month << “月” << _day << “日” << endl;
这一行其实是多个函数的调用,
先执行out<<_year,
它会调用库里的函数:ostream& operator<< (int val);输出
ostream&也就是out作为返回值又变成:out << “年” << _month << “月” << _day << “日” << endl;然后再输出。

到此刻,我们调用cout<<d1时发现会报错,这是为什么呢?

我们将调用void Date::operator<<(ostream& out)这个函数的式子写出来其实是: d1.operator<<(cout);写成这样就可以正常调用。
即d1<<cout。

  其实原因很简单:在运算符重载过程中,参数顺序和操作数顺序必须保持一致。
在这里插入图片描述

我们实际想要写成:cout<<d1,
则参数顺序则应该为:ostream Date
但是存在一个问题,这个函数是Date类中的成员函数,它有隐含一个this指针,把第一个参数占用了,ostream则不能作为第一个参数。此时我们只能将其重载成全局函数。

总结起来就是:operator<<想重载为成员函数,可以,但是使用时d1<<cout不符合习惯,建议重载成全局函数。
如下:

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

在这里插入图片描述
  此时会出现一个私有不可访问的问题,为方便使用,我们先将私有成员变量设为公有。此时可以正常使用,但当我们想连续输出时,如:

cout << d1 << d2;

  此时编译器又会继续报错。因为函数调用会先调用cout << d1,此时没有返回值,所以会报错,我们应该有个返回值,且这个返回值应该是cout,才能使得表达式继续执行,变为cout << d2,就可以连续输出,又因为out是cout的引用,即out是cout的别名,只要返回out即可,所以函数可改为:

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

自定义类型的流提取重载

  与自定义类型的流插入重载一致,就不再细说,直接得代码:

//函数的声明
istream & operator>>(istream & in, Date & d);
//函数的定义
istream& operator>>(istream& in, Date& d)
{
	cout << "请依次输入年月日:" << endl;
	in >> d._year >> d._month >> d._day;
	return in;
}

  这时我们也可以将上节课写的日期检查写入:

istream& operator>>(istream& in, Date& d)
{
	cout << "请依次输入年月日:" << endl;
	in >> d._year >> d._month >> d._day;
	if (!d.CheakDay())
	{
		cout << "日期非法" << endl;
	}
	return in;
}

解决私有问题

  将函数在类中声明为友元函数,这在类和对象终章会讲到。
  代码如下:

class Date
{
    //声明友元函数
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}
istream& operator>>(istream& in, Date& d)
{
	cout << "请依次输入年月日:" << endl;
	in >> d._year >> d._month >> d._day;
	if (!d.CheakDay())
	{
		cout << "日期非法" << endl;
	}
	return in;
}

  声明函数是类的朋友,则函数可以访问类中的所有成员,友元的语法就是这么简单。

日期类总接口

  补充了这两个流的重载,我们可以将Date.h完善:

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		if (!CheakDay())
		{
			cout << "日期非法" << endl;
		}
	}
	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		static int MonthDayArr[] = { 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 MonthDayArr[month];
	}

	bool CheakDay()
	{
		if (_year <= 0 || _month <= 0 || _month > 12 || _day<0 || _day>GetMonthDay(_year, _month))
			return false;
		else
			return true;
	}
	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 n);
	Date operator+(int n);

	Date& operator-=(int n);
	Date operator-(int n);

	Date& operator++();
	Date& operator--();
	Date operator++(int);
	Date operator--(int);

	int operator-(const Date& d)const;
private:
	int _year;
	int _month;
	int _day;
};

请添加图片描述

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

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

相关文章

四款免费文案生成器app,你的文案创作神器

文案创作不仅需要创意和洞察力&#xff0c;还需要对语言的精准掌握。对于许多个人创作者和中小企业来说&#xff0c;聘请专业文案人员可能成本过高&#xff0c;而自己创作又可能面临灵感枯竭的困境。这时&#xff0c;免费的文案生成器App就显得尤为重要。免费文案生成器app的出…

Electron学习笔记(二)Hello World

目录 前言 运行主进程 创建界面 使用窗口打开界面 管理窗口的生命周期 关闭所有窗口时退出应用 (Windows & Linux)​ 如果没有窗口打开则打开一个窗口 (macOS) 使用预加载脚本访问渲染器的Node.js 添加你自己的功能 完整代码展示 效果展示 前言 接上一篇文章 …

JWT详细解析

目录 1. 什么是JWT&#xff1f; 2. 前后端完全分离认证问题 3. JWT的原理 4. JWT的数据结构 5. Header 6. Payload 7. Signature 8.JWT的使用方式 1. 什么是JWT&#xff1f; Json web token (JWT)&#xff0c;是为了在网络应用环境间传递声明而执行的一种基于JSON的开放…

nginx服务---负载均衡、平滑升级

一、nginx服务配置属性监控、nginx代理服务和nginx的IP访客黑名单 1.属性监控 通过在编译时加入 nginx 的 ngx_http_stub_status_module 模块可以实时监控以下基本的指标&#xff1a; 部署过程&#xff1a; 在配置文件/usr/local/nginx/conf/nginx.conf中的server模块中&…

【uniapp离线打包】(基于Android studio)

文章目录 uniapp打包官方教程入口一、准备工作(工具三大件)二、准备工作&#xff08;Android壳和uniapp包&#xff09;导入Android壳生成uniapp包将uniapp包导入android壳 三、准备工作&#xff08;证书、&#xff09;准备Android平台离线签名证书 四、修改配置参数build.gradl…

Data Augmentation数据增强

目录 数据增强是什么 为什么数据增强 数组增强分类 有监督数据增强 无监督数据增强 数据增强是什么 数据增强又称数据扩增&#xff0c;是一种通过应用合理且随机的变换&#xff08;例如图像位移、旋转&#xff09;来增加训练集多样性的技术。让有限的数据产生等价于更多数…

卷积神经网络(五)---图像增强的方法

前面的部分专注于卷积神经网络的层结构介绍&#xff0c;同时还介绍了到目前为止比较出名的卷积神经网络&#xff0c;接着使用比较复杂的卷积神经网络提高了 MNIST 数据集的准确率。下面将从另外的角度——图像增强的方面入手&#xff0c;提高模型的准确率和泛化能力。 一直以来…

C# 弃元的详解与示例

文章目录 1. 什么是弃元&#xff1f;2. 弃元的语法3. 弃元的应用场景4. 示例代码5. 总结 在C# 7.0及更高版本中&#xff0c;弃元&#xff08;Discard&#xff09;是一个新的语言特性&#xff0c;允许开发者在特定情况下忽略某些值。这在处理元组、解构操作或其他只需要部分值的…

【区块链+绿色低碳】泸州:“绿芽积分”号召全民绿色减碳 | FISCO BCOS应用案例

2021 年 6 月 5 日&#xff0c; 首个基于“绿普惠云”所构建的政府级碳普惠平台“泸州市‘绿芽积分’”在生态环境部 2021 年 六五世界环境日国家主场活动中展示&#xff0c;并跻身进入生态环境部“提升公民生态文明意识行动计划”2021 十佳公众 参与案例。 “绿普惠云”是为政…

精通推荐算法11:基于异构图游走的Graph Embedding

DeepWalk、Line和Node2vec对图结构数据进行随机游走&#xff0c;成功将其转化为一个序列问题&#xff0c;并利用Word2vec训练得到节点的Embedding向量。但它们都基于同构图&#xff0c;其节点均属于同一种类型。但现实世界的数据网络大多基于异构图&#xff0c;其节点类型以及节…

【Linux】全志Tina配置log串口信息以及env信息的方法

一、文件位置 V:\f1c100s\Evenurs\f1c100s\tina\device\config\chips\c200s\configs\F1C200s\linux\env-3.10.cfg 二、文件内容 三、介绍 console&#xff1a;串口信息 version&#xff1a;版本信息 appAB&#xff1a;ab区信息 cma&#xff1a;cma容量 四、总结 在此文…

【HarmonyOS】鸿蒙中如何获取资源文件的指定类型 fd,string,Uint8Array,RawFileDescriptor

【HarmonyOS】鸿蒙中如何获取资源文件的指定类型 fd&#xff0c;string&#xff0c;Uint8Array&#xff0c;RawFileDescriptor 一、问题背景&#xff1a; 众所周知&#xff0c;在鸿蒙中的资源分为media和rawfile。两者的区别对标android工程一致&#xff0c;后者是其他类型文…

高月供,高负债,有没有好的办法去解决?

朋友们&#xff0c;有没有过这样的经历&#xff0c;觉得手里那堆贷款账户和每个月高高的月供&#xff0c;就像两座大山压得你喘不过气&#xff1f;特别是想从网贷的高利贷坑跳到银行的低息怀抱&#xff0c;却屡遭拒绝&#xff0c;那种无力感和自我怀疑&#xff0c;简直让人崩溃…

【城市数据集】世界城市数据库和访问门户工具WUDAPT

世界城市数据库和访问门户工具WUDAPT WUDAPTLCZ分类具体步骤参考 在 城市气候研究中&#xff0c;用于描述城市特征的数据集一般采用基于类别的传统方法&#xff0c;将城市地区分为数量有限的类型&#xff0c;从而导致精确度下降。越来越多的新数据集以亚米微尺分辨率描述城市的…

嵌入式学习Day17---Linux软件变编程

目录 ​编辑 一、Linux 系统 1.1.Linux服务器 1.2.Linux嵌入式 1.3.Linux系统上的软件开发 1.操作系统 2.Linux内核 3.man手册 1.4.shell命令 1.基本命令 2.文件查看命令 3.文件查找命令 4.压缩解压文件 5.其他命令 6.通配符 7.管道 8.重定向 1.5.虚拟机上网 1.NAT模式 …

JS学习(变量、数据类型、运算符以及流程控制语句)

目录 一、变量 二、数据类型 三、运算符 四、类型转换 &#xff08;1&#xff09;字符串类型转为数字 &#xff08;2&#xff09;其他类型转为boolean&#xff08;这些全部都是自动转换&#xff09; 五、流程控制 一、变量 &#xff08;1&#xff09;var&#xff1a;声…

2024西安铁一中集训DAY26 ---- 模拟赛(最短路 + 实数域二分 + 线段树 + 并查集(平面图欧拉定理))

文章目录 前言时间安排与成绩题解A. 江桥的蓝紫灯&#xff08;最短路&#xff09;B. 江桥的破坏行动&#xff08;实数域二分&#xff09;C. 江桥的最小值&#xff08;线段树&#xff09;D. 江桥的山谷&#xff08;并查集&#xff0c;平面图欧拉定理&#xff09; 前言 感觉是做…

Android NDK 编译 libcurl支持https

最后在使用NDK中使用libcurl&#xff0c;由于不同的安卓设备&#xff0c;版本不一样&#xff1b;使用so时&#xff0c;会导致报错dlopen时找不到某函数或出错。 最后直接使用libcurl.a后&#xff0c;目前在几款盒子上测试均能正常工作。 libcurl需要支持https得提前编译两个库…

LLM评估 | 大模型评估方法调研--论文解读(持续更新ing!!!)

目录 LLM-based NLG Evaluation: Current Status and ChallengesAdaptEval: Evaluating Large Language Models on Domain Adaptation for Text SummarizationThe Potential and Challenges of Evaluating **Attitudes, Opinions, and Values** in Large Language ModelsEvalLM…

揭秘高效语音转文字工具:让沟通更便捷

嘿&#xff0c;各位办公室的小伙伴们&#xff0c;今儿咱们来聊聊那些能让咱们文员生活大变样的神器——特别是那些能把咱们嘴里嘟囔的话儿&#xff0c;瞬间变成电脑里整整齐齐文字的语音转文字工具。说起来&#xff0c;自从有了这些宝贝&#xff0c;我感觉自己都快能飞起来了&a…