当前位置: 首页 > news >正文

C++类与对象(5)—流运算符重载、const、取地址

目录

一、流输出

1、实现单个输出

2、实现连续输出

二、流输入

  总结:

三、const修饰

四、取地址

.取地址及const取地址操作符重载

五、[ ]运算符重载


一、流输出

1、实现单个输出

创建一个日期类。

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

以前我们在日期类中想要输出日期,都需要在类中自己创建一个用于输出的成员函数。

	void Print(){cout<< _year << "年" << _month << "月" << _day << "日" << endl;}

对于内置类型我们可以直接用cout<<输出其值。

我们也可以重载流提取<<实现输出内置类型的成员值,首先来了解一下cout的由来。

  • iostream 是 C++ 标准库中的一个头文件,它包含了用于输入和输出的流类的定义。iostream 头文件中定义了 istream 和 ostream 这两个基类,它们分别用于输入和输出操作。

  • ostream 是 iostream 头文件中定义的一个类,它是输出流的基类。ostream 类提供了输出操作的基本功能和接口,例如 << 操作符用于输出数据到流中。

  • cout 是 ostream 类的一个对象,它是标准输出流对象。cout 对象可以使用 << 操作符将数据输出到标准输出设备(通常是控制台)。

iostream 是一个头文件,ostream 是 iostream 中定义的输出流基类,而 cout 是 ostream 类的一个对象,用于将数据输出到标准输出设备。通过使用 cout 对象和 << 操作符,我们可以方便地将数据输出到控制台。

 现在在类中实现<<重载:

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

ostream& 是一个引用类型,表示对输出流对象的引用,通过使用 ostream& 引用类型,可以将输出流对象传递给操作符重载。

 当我们要使用运算符重载<<时,需要使用如下形式:

d1 << cout;//或者d1.operator<<(cout);

运算符重载<<的第一个参数为左操作数,第二个参数为右操作数。

虽然这种形式可以输出我们想要的结果,但这与我们使用的cout<<d1这种常规方式有所出入。

我们可以对其进行修改,将<<运算符重载作为全局函数,将输出流对象的引用作为第一个参数,日期类对象的引用作为第二个参数。

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

同时,为了使全局<<运算符重载能够访问到日期类对象d的私有成员变量,可以在日期类中创建友元函数声明,这样就可以访问对象的成员了。

friend void operator<<(ostream& out, const Date& d);

下面来测试一下: 

class Date
{friend void operator<<(ostream& out, const Date& d);
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout<< _year << "年" << _month << "月" << _day << "日" << endl;}
private:int _year;int _month;int _day;
};
void operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}void Test()
{Date a(2023, 11, 24);a.Print();cout << a;
}int main()
{Test();return 0;
}

 成功实现运算符<<的重载。

 

2、实现连续输出

如果是下面这种连续输出呢?

void Test2()
{Date a(2023, 11, 24);Date b(2023, 11, 25);cout << a << b << endl;
}

这时编译器会报错。 

 

 为了支持连续输出的形式,我们需要为<<重载增加返回值。

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

同时,友元函数声明也要修改一下:

friend ostream& operator<<(ostream& out, const Date& d);

 测试一下:

class Date
{friend ostream& operator<<(ostream& out, const Date& d);
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout<< _year << "年" << _month << "月" << _day << "日" << endl;}
private:int _year;int _month;int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}
void Test2()
{Date a(2023, 11, 24);Date b(2023, 11, 25);cout << a << b << endl;
}
int main()
{Test2();return 0;
}

成功实现连续输出: 

二、流输入

iostreamistream 和 cin 是 C++ 中用于输入的相关类和对象。

  • iostream 是 C++ 标准库中的一个头文件,它包含了用于输入和输出的流类的定义。iostream 头文件中定义了 istream 和 ostream 这两个基类,分别用于输入和输出操作。

  • istream 是 iostream 头文件中定义的一个类,它是输入流的基类。istream 类提供了输入操作的基本功能和接口,例如 >> 操作符用于从流中读取数据。

  • cin 是 istream 类的一个对象,它是标准输入流对象。cin 对象可以使用 >> 操作符从标准输入设备(通常是键盘)读取数据。

总结:iostream 是一个头文件,istream 是 iostream 中定义的输入流基类,而 cin 是 istream 类的一个对象,用于从标准输入设备读取数据。通过使用 cin 对象和 >> 操作符,我们可以方便地从键盘输入数据。

 下面来实现流提取>>运算符重载,与流插入<<实现方式相同。

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

 测试一下

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){_year = year;_month = month;_day = day;}void Print(){cout<< _year << "年" << _month << "月" << _day << "日" << endl;}
private:int _year;int _month;int _day;
};
istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}
void Test3()
{Date d;cin >> d;cout << d;
}
int main()
{Test3();return 0;
}

成功实现流提取运算符重载。 

总结:

如果类的声明和定义是分文件的,我们一般把流提取和流插入运算符重载放到作为内联函数放到头文件中,这样省去了链接的过程,在编译过程就能call地址。

inline ostream& operator<<(ostream& out, const 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;
}
  • 在C++中,如果一个成员函数直接在类内部定义,它会被视为内联函数。内联函数的定义与声明都在类的定义中,这样编译器可以在调用处将函数的代码插入到调用位置,而不是通过函数调用的方式执行。
  • 通常情况下,短小的函数适合作为内联函数,因为内联函数的调用开销较小,可以避免函数调用的额外开销。将这样的函数定义在类内部可以方便地将其声明和定义放在一起,提高代码的可读性和维护性。
  • 然而,需要注意的是,编译器是否将一个在类内部定义的成员函数视为内联函数,最终还是由编译器决定。编译器可能会根据一些因素(如函数的复杂性、调用频率等)来决定是否将其内联展开。
  • 总之,将短小的函数定义在类内部可以被视为内联函数,这样可以提高代码的执行效率和可读性。但最终是否内联展开还是由编译器决定。

三、const修饰

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

我们来看下面代码:

class A {
public:void Print() {cout << _a << endl;}
private:int _a = 1;
};
int main()
{A aa;aa.Print();return 0;
}

成功输出: 

如果用const修饰aa,这样可以吗? 

const A aa;

编译后程序报错: 

 

这是因为造成了权限放大的问题。

 Print函数的参数是A*this,aa的类型是const A*,所以aa调用Print函数会造成权限放大,而且如果权限平移,在this指针前用const修饰,这样也是禁止的,我们不能修改this指针。

这时有一个新的间接方法:

  • 语法规定叫const成员函数,const修饰*this,也就意味着this的类型变成const A*类型。
  • 内部不改变成员变量的成员函数时,最好加上const,const对象和普通对象都可以调用。

 这时我们就可以对C++类与对象(4)—日期类的实现这篇文章的Date.h文件中部分成员函数进行const修饰了。

#include <iostream>
#include <assert.h>
using namespace std;class Date {
public:Date(int year = 0, int month = 0, int day = 0);void Print();int GetMonthDay(int year, int month) 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;bool operator>=(const Date& d) const;Date& operator+=(int day);Date operator+(int day) const;Date& operator-=(int day);// d1 - 100Date operator-(int day);// d1 - d2;int operator-(const Date& d) const;// ++d1Date& operator++();// d1++Date operator++(int);Date& operator--();Date operator--(int);private:int _year;int _month;int _day;
};

四、取地址

.取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成

class Date
{
public :Date* operator&(){return this ; }const Date* operator&()const{return this ;}
private :int _year ; // 年int _month ; // 月int _day ; // 日
};
这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需
要重载,比如想让别人获取到指定的内容。

五、[ ]运算符重载

class Array
{
public:int& operator[](int i){assert(i < 10);return _a[i];}const int& operator[](int i) const{assert(i < 10);return _a[i];}
private:int _a[10];int _size;
};void Func(const Array& aa)
{for (int i = 0; i < 10; ++i){//aa[i]++;cout << aa[i] << " ";}
}

首先,我们来看Array类:

  • Array类定义了一个私有的整型数组_a,大小为10,以及一个私有的整型变量_size

  • Array类重载了[]运算符,这样我们就可以像使用普通数组一样使用Array类的对象。

  • operator[]函数有两个版本,一个是非常量版本,一个是常量版本。非常量版本返回一个可修改的引用,常量版本返回一个不可修改的常量引用。

  • operator[]函数中,使用了assert函数来确保索引i小于10,防止数组越界。

然后,我们来看Func函数:

  • Func函数接受一个Array类的常量引用作为参数。因为参数是常量引用,所以我们不能在函数中修改参数的值。

  • Func函数中,有一个循环,循环变量i从0遍历到9。在循环体中,首先注释掉了aa[i]++,这是因为aa是一个常量引用,我们不能修改它的值。然后,使用cout打印出aa[i]的值,然后打印一个空格。

举个例子,如果我们创建一个Array类的对象a,并初始化_a数组为0到9,然后调用Func(a),那么控制台上会打印出0 1 2 3 4 5 6 7 8 9

相关文章:

C++类与对象(5)—流运算符重载、const、取地址

目录 一、流输出 1、实现单个输出 2、实现连续输出 二、流输入 总结&#xff1a; 三、const修饰 四、取地址 .取地址及const取地址操作符重载 五、[ ]运算符重载 一、流输出 1、实现单个输出 创建一个日期类。 class Date { public:Date(int year 1, int month 1,…...

Vue框架学习笔记——事件修饰符

文章目录 前文提要事件修饰符prevent&#xff08;常用&#xff09;stop&#xff08;不常用&#xff09;事件冒泡stop使用方法三层嵌套下的stop三层嵌套看出的stop&#xff1a; once&#xff08;常用&#xff09;capture&#xff08;不常用&#xff09;self&#xff08;不常用&a…...

嵌入式虚拟机原理

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…...

AMESim|Make failed:Unable to create an excutable for the system

最近在AMESIM与MATLAB进行联合仿真的时候遇到如下问题&#xff1a; Make failed:Unable to create an excutable for the system. 看了网上的解决办法如下 配置环境变量重装AMESIM&#xff0c;有顺序要求&#xff0c;首先是VS&#xff0c;然后是AMESIM与MATLAB。在AMESIM安装…...

OpenHarmony之NAPI框架介绍

张志成 诚迈科技高级技术专家 NAPI是什么 NAPI的概念源自Nodejs&#xff0c;为了实现javascript脚本与C库之间的相互调用&#xff0c;Nodejs对V8引擎的api做了一层封装&#xff0c;称为NAPI。可以在Nodejs官网&#xff08;https://nodejs.org/dist/latest-v20.x/docs/api/n-api…...

计算机网络之网络层

一、概述 主要任务是实现网络互连&#xff0c;进而实现数据包在各网络之间的传输 1.1网络引入的目的 从7层结构上看&#xff0c;网络层下是数据链路层 从4层结构上看&#xff0c;网络层下面是网络接口层 至少我们看到的网络层下面是以太网 以太网解决了什么问题&#xff1f; 答…...

【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析模拟实现

&#x1f308;write in front :&#x1f50d;个人主页 &#xff1a; 啊森要自信的主页 ✏️真正相信奇迹的家伙&#xff0c;本身和奇迹一样了不起啊&#xff01; 欢迎大家关注&#x1f50d;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;>希望看完我的文章对你有小小的帮助&am…...

浅谈电力设备智能无线温度检测系统

安科瑞 华楠 摘要&#xff1a;在长期工作中&#xff0c;由于设备基础变化、温湿度变化、严重超负荷运行、触点氧化等原因造成的电力设备压接不紧&#xff0c;触头接触部分发生改变。终导致接触电阻增大&#xff0c;造成巨大的风险隐患。本系统将通过无线测温的方式&#xff0c…...

通过ros系统中websocket中发送sensor_msgs::Image数据给web端显示(二)

通过ros系统中websocket中发送sensor_msgs::Image数据给web端显示(二) mp4媒体流数据 #include <ros/ros.h> #include <signal.h> #include <sensor_msgs/Image.h> #include <message_filters/subscriber.h> #include <message_filters/synchroniz…...

LeetCode [简单] 283. 移动零

给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 283. 移动零 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 快慢指针&…...

深信服实验学习笔记——nmap常用命令

文章目录 1. 主机存活探测2. 常见端口扫描、服务版本探测、服务器版本识别3. 全端口&#xff08;TCP/UDP&#xff09;扫描4. 最详细的端口扫描5. 三种TCP扫描方式 1. 主机存活探测 nmap -sP <靶机IP>-sP代表 2. 常见端口扫描、服务版本探测、服务器版本识别 推荐加上-v参…...

面试:Kubernetes相关问题

文章目录 Kubernetes的工作流程可以分为以下几个步骤&#xff1a;简述Kubernetes中的Deployment、StatefulSet、DaemonSet的区别在Kubernetes中&#xff0c;如何进行存储管理在Kubernetes中&#xff0c;如何实现滚动升级和回滚在Kubernetes中&#xff0c;如何进行日志和监控的管…...

Go 本地搭建playground

搭建go playground 的步骤 1、安装docker 如果你使用的Ubuntu&#xff0c;docker的安装步骤可以参见这里&#xff0c;这是我之前写的在Ubuntu18.04下安装fabric&#xff0c;其中有docker的安装步骤&#xff0c;这里就不再赘述了。 CentOS下安装docker的&#xff0c;可以参见…...

Mybatis-plus常见标签

1.< 代表小于号&#xff08;<&#xff09;2.> 代表大于号&#xff08;>&#xff09;3.&le; 代表小于或等于符号&#xff08;≤&#xff09;4.&ge; 代表大于或等于符号&#xff08;≥&#xff09;5.< 代表<6.> 代表>7.ne; 代表不等于 <>8…...

一致性 Hash 算法 Hash 环发生偏移怎么解决

本篇是对文章《一文彻底读懂一致性哈希算法》的重写&#xff0c;图文并茂&#xff0c;篇幅较长&#xff0c;欢迎阅读完提供宝贵的建议&#xff0c;一起提升文章质量。如果感觉不错不要忘记点赞、关注、转发哦。原文链接&#xff1a; 《一文彻底读懂一致性Hash 算法》 通过阅读本…...

Javaweb之Vue组件库Element的详细解析

4 Vue组件库Element 4.1 Element介绍 不知道同学们还否记得我们之前讲解的前端开发模式MVVM&#xff0c;我们之前学习的vue是侧重于VM开发的&#xff0c;主要用于数据绑定到视图的&#xff0c;那么接下来我们学习的ElementUI就是一款侧重于V开发的前端框架&#xff0c;主要用…...

IBM X3650M4安装ESXI6.5卡在/lsl_mr3.v00

环境&#xff1a;IBM X3650M4服务器双盘配置raid1&#xff0c;通过rufus制作启动U盘&#xff0c;安装VMware Vsphere 5.5系统 问题&#xff1a;卡在/lsi_mr3.v00界面无法往下运行&#xff08;两台配置一样的机器遇到同样的问题&#xff09; 解决方案&#xff1a; 直接在U盘根…...

【Python3】【力扣题】338. 比特位计数

【力扣题】题目描述&#xff1a; 题解&#xff1a;从0到n的整数&#xff0c;逐一统计二进制中1的个数&#xff0c;记录在一个新列表中。 【Python3】代码&#xff1a; 1、解题思路&#xff1a;Python函数。 知识点&#xff1a;bin(...)&#xff1a;转为二进制字符串&#xff…...

Lubuntu 23.10用户可使用LXQt 1.4桌面

导读在众多 Lubuntu 用户的要求下&#xff0c;Lubuntu 开发人员决定将 LXQt 1.4 桌面环境向后移植到最新的 Lubuntu 23.10 &#xff08;Mantic Minotaur&#xff09; 版本。 是的&#xff0c;您没看错&#xff0c;您现在可以使用官方的 Lubuntu Backports PPA&#xff08;个人软…...

语音识别入门——常用软件及python运用

工具以及使用到的库 ffmpegsoxaudacitypydubscipylibrosapyAudioAnalysisplotly 本文分为两个部分&#xff1a; P1&#xff1a;如何使用ffmpeg和sox处理音频文件 P2&#xff1a;如何编程处理音频文件并执行基本处理 P1 处理语音数据——命令行方式 格式转换 ffmpeg -i video…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...

C++_哈希表

本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、基础概念 1. 哈希核心思想&#xff1a; 哈希函数的作用&#xff1a;通过此函数建立一个Key与存储位置之间的映射关系。理想目标&#xff1a;实现…...

WEB3全栈开发——面试专业技能点P7前端与链上集成

一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染&#xff08;SSR&#xff09;与静态网站生成&#xff08;SSG&#xff09; 框架&#xff0c;由 Vercel 开发。它简化了构建生产级 React 应用的过程&#xff0c;并内置了很多特性&#xff1a; ✅ 文件系…...

篇章二 论坛系统——系统设计

目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...