当前课程知识点:基于Linux的C++ >  第十讲 操作符重载 >  10.11 流操作符重载(二) >  LinuxCPP1011

返回《基于Linux的C++》慕课在线视频课程列表

LinuxCPP1011在线视频

LinuxCPP1011

下一节:LinuxCPP1012

返回《基于Linux的C++》慕课在线视频列表

LinuxCPP1011课程教案、知识点、字幕

接下来一个地方就是我们的操纵符

为了控制这个流的输出的过程

不仅仅我们以前面那个模式来去写

它要提供一系列的操纵符来控制

整个流的输入输出的格式

你看到我们前面设了

把它设成16进制的设精度

那种东西都叫它的操纵符

你要设定这个流嘛

这个流 它在设计实现中

有一个非常精巧的地方 就是什么呢

就是数据对象实际上是连续输出的

os<

它实际上是一个连续输出的一个过程

如果你把控制这个流的操作的过程

插在这个连续输出的中间

你不就打断了这个连续输出的逻辑了吗

你比如我os<

但是我又想把“<

好吧 你就写os<

然后os<

然后os<

多罗嗦 多麻烦 对吧

你如果按照这个模式来写

流的连续操控就被打断了

那流还有意义吗

我们实现流的最主要的目的

就是想实现一个连续操作嘛

你自来水管一打开

那水就“哗哗哗”往下流啊

要不怎么叫流呢 对不对

它是个连续动作啊

所以流式操作必须保证这个连续性

那么所有对流的格式

进行控制的那些操作

必须是以输出对象

或输入对象一样的方式进行处理

也就是说 控制流格式的那个东西

本身应该可以作为流的那个参数

必须做到这一条 那么怎么做它呢

那就manipulator操纵符

它做的就是这个事情

实现操纵符的目的就在这里

操纵符有两种

一种是没有参数的操纵符

那么它在实现上

使用的其实就是一个函数指针

还有一种 就是带着一个单参数的操纵符

在实现上 所有的这种单参数的操纵符

它都是一个函子 什么叫函子呢

函子就是带有函数指针功能的

操纵符类的一个对象

它在实现上 实际上是重载了

函数调用操作符的一个操纵符类

然后你构造这个操纵符类的一个对象

然后在那个对象上面

调用它重载的函数调用操作符

然后它就表现行为就像一个函数一样了

这就叫一个函子

有的时候我们称它为函数对象

叫function object

有的时候你就直接称叫functor 就叫函子

我就把它翻译成“函子” 就这个意思

函子怎么实现 怎么用

我们下一讲讲泛型编程的时候

也会专门去讨论它

现在同学们只需要知道

所有的流式的单参数的操纵符

在实现上都是函子

所以相当精巧地

实现了我们流式的连续操控

你比如讲

std::cout << "Hello World!" << std::endl

这就是一个操纵符

表示一个换行的动作 无参数

我定义一个整型量n 初始化成1024

std::cout << std::dec << n << '\n' << std::hex

<< n << std::endl(dec:decimal表示它是个十进制;

hex:十六进制)

你看 我就把这些操纵符:

dec操纵符、hex操纵符

(一个是十进制操纵符一个十六进制操作符)、

一个endl操纵符(换行符)

这三个操纵符

我就直接地插在了流式操作的中间

这样的话我就没有打断

整个流的连续书写特性

数据流动的关系也没有被临时地中断

你看到 这样的书写

是不是看上去非常自然、灵巧

这是操纵符的最重要的一个地方

就按照这个模式去工作的

在标准的流类库里面

它提供了很多个操纵符

从boolalpha、dec、endl 一直往后

1个、2个、3个、4个、5个、6个、

7个、8个、9个、10个、11个

我们这里11个 又来11个 还有呢

提供了一堆操纵符 你都可以直接用

接下来就是我们的文件流

文件它和其它的流

有一点点细微的特殊性

就是什么呢 文件一般是保存在我们的

外部存储介质上面的

文件的生命周期本身

可能远远大于我们程序的生命周期

我一个程序 我运行 我得到一个结果

我把这个结果写到这个文件里

我程序就结束了 那个文件还在

我下一次运行这个程序

就从那个文件中把那个数据给读出来

这个动作叫数据的持久化

我能够完成这个动作

就意味着我这个程序要和这个文件

形成一个对应的关系

那么这个数据

怎么从这个文件中流入流出呢

那么我们就需要架构文件流

从数据流动角度来讲

除了源和目的发生了变化

文件流本身的设计和我们标准流的设计

它的基本原理实际上是一致的

但是文件的操作呢 它又很特殊

因为它是外部一个资源

我们怎么去操控它呢

需要和操作系统进行打交道

所以它又有一些自己独有的特性

从文件操作角度来讲

我们最重要的是要完成文件的读写操作

我从文件中读数据

把这个数据写到文件里 对吧

我们主要的是使用文件指针的模式

来操纵我们这个文件读写的位置

我要决定我这个数据写在文件什么地方呀

对吧 如果我们需要文件进行读写操作

那么我们就需要文件指针

这样的一个指针

它就代表了文件的当前访问位置

你的数据读取或写入

将从文件的什么地方开始 就这个意思

老式的C语言 有的时候呢

使用文件句柄或者文件描述符

来描述打开的文件数据对象

它打开某个数据对象 那怎么描述它呢

有的系统使用文件句柄

有的系统使用文件描述符

不是使用我们标准C++里面提到的文件流

你注意这一点就行了

文件流 你要想使用的话

必须包含我们这个头文件“fstream”

它的内容都实现在“fstream”这个头文件里

要按照特定的格式重载我们的流操作符

这样的话才能够把这个指定的对象

按照一个特定的方式去流出去

否则的话 你就得一个成员、一个成员地

自己手工去写操作 那就麻烦了

因为好多成员都是私有的

在这种情况下你必须提供

对应的Get/Set函数

你才能够操作 对吧

而且那个格式就很费劲了

你要一个一个地去写

对于这个类的使用者来讲

输出一次类的信息确实很麻烦

如果对象很多

那代码写出来很长的 会崩溃的

那么对于库的设计者来讲呢

你为了让它不崩溃

你就得重载类的流操作符

你必须要做到这个事情

使用者来讲呢 那就简单了

一旦我们重载了流操作符

那么只需要创建我们的文件流对象

然后进行输入输出 完事了

那个使用就简单了

文件流有几个主要的打开方式

第一个 有一种追加模式打开

一种是二进制格式的打开

或者输入模式打开 输出模式打开 等等

所有这些文件的打开模式

在我们标准流类库里

都有一些专门的介绍

每一个流打开以后

它都有一个特定的流状态

流状态就表示我们在流进行操纵过程中

它成功或失败的像这样的一个状态信息

你比如讲 有一个goodbit

这样一个状态 表示好位状态

就是什么呢 当这个操作做完了以后

流是完好无损的

操作成功了 就这个意思

badbit 坏位 就表示操作失败

像eofbit 表示流结束位

像failbit 流操作失败的时候

我们就会设定它 它就失败了

这个failbit 实际上有可能恢复的错误

你比如我打开一个文件

我想写入 但是那个文件不能写

它被别人锁定了

那么就会返回一个failbit 一个坏位

不是说那个文件真地没有

不 那个文件有

它只是被锁定了 临时被锁定了

你等一会儿它就能写了

有可能吧 这是当然有可能的

那么在这种情况下面

它不是说它不能写 然后重试

没准retry一下 重试一遍 它就能写了

这种情况太正常了

所以这返回的可能就是一个failbit

如果那个文件本身就损坏了 磁盘坏了

那个地方的数据压根就找不着了

那肯定返回的就是一个badbit

那是一个坏位

这个情况下一般是没有办法恢复的

是这个意思

流操作本身都可能——任何一个流操作

都可能——影响我们的流状态

而流状态当然对流操作行为

其实也能够造成影响

一旦你流状态存在这样的错误

那么所有的I/O操作 它都会失效

不做了 有问题了

这个操作肯定都有问题了

出现了一个failbit 还做什么呢

对吧 不行了

现在操作都失效了 不做了

是这个意思 注意这一点

可以通过一系列的成员函数

来测试我们的流处于什么样的状态

你比如说 good测试 eof测试

fail测试 bad测试 等等

你还可以使用它重载的“!”操作符

和哑型指针操作符

来进行一些特定的操作

比如讲“!”操作符

它等价于什么呢 等价于我们的fail

当操作这个流的时候

一会儿向这个流中写入一部分数据

一会儿又从流中再读取一部分数据

那个流读取的位置

它有一个文件指针指向它

就会时刻发生变化

我想知道这个位置指针到底指向了哪里

或者我想把它设到一个特定的地方

那么我就需要对这个流进行定位

这就是流的位置指针

位置指针 它指向我们下一次读写操作

将要发生的那个地方

正常情况下是这个模式

它跟着我们的输入输出的这个动作

会不断发生变化的

对于一个单向流 一个位置指针就够了

因为它是一个单向流动

如果是一个双向流动

又有输入又有输出 是个双向流动

那么这个时候我就需要两个文件指针

对吧 一个方向是一个

这是两个 双文件指针

流位置指针 想知道它在什么地方

那么你就可以调用成员函数tellp/tellg

可以获得位置指针的位置信息

写指针用tellp 读指针使用tellg

你获得了以后

想把这个文件指针做一些改变

那么你就可以用seekp/seekg

然后去定位

这样一个位置指针到指定的地方

就按照这个模式就行

seekp处理的就是输出目的的 写的

seekg呢 就是读取的 就输入目的

当你用seekp和seekg进行流指针定位的时候

要注意可以提供一个单参数的版本

就是可以使用获取的位置指针来去做它

如果需要传递一个额外参数

那就是需要传递一个偏移量

传递一个定位的基准

从流的开始位置开始计算偏移量的话

那就用beg这个定位基准

从当前位置开始计算偏移 就用cur

从流的最结尾 文件的结尾开始定位

那就用end这个定位基准

基于Linux的C++课程列表:

第一讲 C/C++基本语法元素

-1.1 提纲

--LinuxCPP0101

-1.2 程序设计的基本概念

--LinuxCPP0102

-1.3 简单C/C++程序介绍

--LinuxCPP0103

-1.4 程序设计的基本流程

--LinuxCPP0104

-1.5 基本语法元素

--LinuxCPP0105

-1.6 程序设计风格

--LinuxCPP0106

-1.7 编程实践

--LinuxCPP0107

-第一讲 C/C++基本语法元素--编程实践提交入口

第二讲 程序控制结构

-2.1 提纲

--LinuxCPP0201

-2.2 结构化程序设计基础

--LinuxCPP0202

-2.3 布尔数据

--LinuxCPP0203

-2.4 分支结构

--LinuxCPP0204

-2.5 break语句

--LinuxCPP0205

-2.6 循环结构

--LinuxCPP0206

-2.7 编程实践

--LinuxCPP0207

-第二讲 程序控制结构--编程实践提交入口

第三讲 函数

-3.1 提纲

--LinuxCPP0301

-3.2 函数声明、调用与定义

--LinuxCPP0302

-3.3 函数调用栈框架

--LinuxCPP0303

-3.4 编程实践

--LinuxCPP0304

-第三讲 函数--编程实践提交入口

第四讲 算法

-4.1 提纲

--LinuxCPP0401

-4.2 算法概念与特征

--LinuxCPP0402

-4.3 算法描述

--LinuxCPP0403

-4.4 算法设计与实现

--LinuxCPP0404

-4.5 递归算法(一)

--LinuxCPP0405

-4.6 递归算法(二)

--LinuxCPP0406

-4.7 容错与计算复杂度

--LinuxCPP0407

-4.8 编程实践

--LinuxCPP0408

-第四讲 算法--编程实践提交入口

第五讲 程序组织与开发方法

-5.1 提纲

--LinuxCPP0501

-5.2 库与接口

--LinuxCPP0502

-5.3 随机数库(一)

--LinuxCPP0503

-5.4 随机数库(二)

--LinuxCPP0504

-5.5 作用域与生存期

--LinuxCPP0505

-5.6 典型软件开发流程(一)

--LinuxCPP0506

-5.7 典型软件开发流程(二)

--LinuxCPP0507

-5.8 编程实践

--LinuxCPP0508

-第五讲 程序组织与开发方法--编程实践提交入口

第六讲 复合数据类型

-6.1 提纲

--LinuxCPP0601

-6.2 字符

--LinuxCPP0602

-6.3 数组(一)

--LinuxCPP0603

-6.4 数组(二)

--LinuxCPP0604

-6.5 结构体

--LinuxCPP0605

-6.6 编程实践

--LinuxCPP0606

-第六讲 复合数据类型--编程实践提交入口

第七讲 指针与引用

-7.1 提纲

--LinuxCPP0701

-7.2 指针基本概念

--LinuxCPP0702

-7.3 指针与函数

--LinuxCPP0703

-7.4 指针与复合数据类型(一)

--LinuxCPP0704

-7.5 指针与复合数据类型(二)

--LinuxCPP0705

-7.6 字符串

--LinuxCPP0706

-7.7 动态存储管理(一)

--LinuxCPP0707

-7.8 动态存储管理(二)

--LinuxCPP0708

-7.9 引用

--LinuxCPP0709

-7.10 编程实践

--LinuxCPP0710

-第七讲 指针与引用--编程实践提交入口

第八讲 链表与程序抽象

-8.1 提纲

--LinuxCPP0801

-8.2 数据抽象(一)

--LinuxCPP0802

-8.3 数据抽象(二)

--LinuxCPP0803

-8.4 链表(一)

--LinuxCPP0804

-8.5 链表(二)

--LinuxCPP0805

-8.6 链表(三)

--LinuxCPP0806

-8.7 链表(四)

--LinuxCPP0807

-8.8 函数指针(一)

--LinuxCPP0808

-8.9 函数指针(二)

--LinuxCPP0809

-8.10 抽象链表(一)

--LinuxCPP0810

-8.11 抽象链表(二)

--LinuxCPP0811

-8.12 编程实践

--LinuxCPP0812

-第八讲 链表与程序抽象--编程实践提交入口

第九讲 类与对象

-9.1 提纲

--LinuxCPP0901

-9.2 程序抽象与面向对象

--LinuxCPP0902

-9.3 类类型

--LinuxCPP0903

-9.4 对象(一)

--LinuxCPP0904

-9.5 对象(二)

--LinuxCPP0905

-9.6 类与对象的成员(一)

--LinuxCPP0906

-9.7 类与对象的成员(二)

--LinuxCPP0907

-9.8 类与对象的成员(三)

--LinuxCPP0908

-9.9 继承(一)

--LinuxCPP0909

-9.10 继承(二)

--LinuxCPP0910

-9.11 继承(三)

--LinuxCPP0911

-9.12 多态(一)

--LinuxCPP0912

-9.13 多态(二)

--LinuxCPP0913

-9.14 编程实践

--LinuxCPP0914

-第九讲 类与对象--编程实践提交入口

第十讲 操作符重载

-10.1 提纲

--LinuxCPP1001

-10.2 四则运算符重载(一)

--LinuxCPP1002

-10.3 四则运算符重载(二)

--LinuxCPP1003

-10.4 关系与下标操作符重载

--LinuxCPP1004

-10.5 赋值操作符重载(一)

--LinuxCPP1005

-10.6 赋值操作符重载(二)

--LinuxCPP1006

-10.7 赋值操作符重载(三)

--LinuxCPP1007

-10.8 赋值操作符重载(四)

--LinuxCPP1008

-10.9 赋值操作符重载(五)

--LinuxCPP1009

-10.10 流操作符重载(一)

--LinuxCPP1010

-10.11 流操作符重载(二)

--LinuxCPP1011

-10.12 流操作符重载(三)

--LinuxCPP1012

-10.13 操作符重载总结

--LinuxCPP1013

-10.14 编程实践

--LinuxCPP1014

-第十讲 操作符重载--编程实践提交入口

第十一讲 泛型编程

-11.1 提纲

--LinuxCPP1101

-11.2 泛型编程概览

--LinuxCPP1102

-11.3 异常处理机制(一)

--LinuxCPP1103

-11.4 异常处理机制(二)

--LinuxCPP1104

-11.5 运行期型式信息(一)

--LinuxCPP1105

-11.6 运行期型式信息(二)

--LinuxCPP1106

-11.7 模板与型式参数化

--LinuxCPP1107

-11.8 题外话:术语翻译

--LinuxCPP1108

-11.9 泛型编程实践(一)

--LinuxCPP1109

-11.10 泛型编程实践(二)

--LinuxCPP1110

-11.11 泛型编程实践(三)

--LinuxCPP1111

-11.12 泛型编程实践(四)

--LinuxCPP1112

-11.13 泛型编程实践(五)

--LinuxCPP1113

-11.14 泛型编程实践(六)

--LinuxCPP1114

-11.15 泛型编程实践(七)

--LinuxCPP1115

-11.16 泛型编程实践(八)

--LinuxCPP1116

-11.17 泛型编程实践(九)

--LinuxCPP1117

-11.18 泛型编程实践(十)

--LinuxCPP1118

-11.19 编程实践

--LinuxCPP1119

-第十一讲 泛型编程--编程实践提交入口

第十二讲 Linux系统编程基础

-12.1 提纲

--LinuxCPP1201

-12.2 程序执行环境(一)

--LinuxCPP1202

-12.3 程序执行环境(二)

--LinuxCPP1203

-12.4 程序执行环境(三)

--LinuxCPP1204

-12.5 程序执行环境(四)

--LinuxCPP1205

-12.6 输入输出(一)

--LinuxCPP1206

-12.7 输入输出(二)

--LinuxCPP1207

-12.8 文件系统

--LinuxCPP1208

-12.9 设备

--LinuxCPP1209

-12.10 库(一)

--LinuxCPP1210

-12.11 库(二)

--LinuxCPP1211

-12.12 makefile文件(一)

--LinuxCPP1212

-12.13 makefile文件(二)

--LinuxCPP1213

-12.14 makefile文件(三)

--LinuxCPP1214

-12.15 编程实践

--LinuxCPP1215

-第十二讲 Linux系统编程基础--编程实践提交入口

第十三讲 进程编程

-13.01 提纲

--LinuxCPP1301

-13.02 进程基本概念

--LinuxCPP1302

-13.03 信号

--LinuxCPP1303

-13.04 进程管理(一)

--LinuxCPP1304

-13.05 进程管理(二)

--LinuxCPP1305

-13.06 进程管理(三)

--LinuxCPP1306

-13.07 进程间通信(一)

--LinuxCPP1307

-13.08 进程间通信(二)

--LinuxCPP1308

-13.09 进程间通信(三)

--LinuxCPP1309

-13.10 进程间通信(四)

--LinuxCPP1310

-13.11 进程池

--LinuxCPP1311

-13.12 编程实践

--LinuxCPP1312

-第十三讲 进程编程--编程实践提交入口

第十四讲 线程编程

-14.1 提纲

--LinuxCPP1401

-14.2 线程基本概念

--LinuxCPP1402

-14.3 线程管理(一)

--LinuxCPP1403

-14.4 线程管理(二)

--LinuxCPP1404

-14.5 线程管理(三)

--LinuxCPP1405

-14.6 线程管理(四)

--LinuxCPP1406

-14.7 线程同步机制(一)

--LinuxCPP1407

-14.8 线程同步机制(二)

--LinuxCPP1408

-14.9 C++11线程库(一)

--LinuxCPP1409

-14.10 C++11线程库(二)

--LinuxCPP1410

-14.11 C++11线程库(三)

--LinuxCPP1411

-14.12 C++11线程库(四)

--LinuxCPP1412

-14.13 C++11线程库(五)

--LinuxCPP1413

-14.14 编程实践

--LinuxCPP1414

-第十四讲 线程编程--编程实践提交入口

第十五讲 网络编程

-15.1 提纲

--LinuxCPP1501

-15.2 Internet网络协议

--LinuxCPP1502

-15.3 套接字(一)

--LinuxCPP1503

-15.4 套接字(二)

--LinuxCPP1504

-15.5 编程实践

--LinuxCPP1505

-第十五讲 网络编程--编程实践提交入口

课程文档

-课程PDF文件

LinuxCPP1011笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。