资源

课程网页
python to c++
c++文档
2019年的PPT

课程目标

  • 了解C++的特性,以及这些存在这些特性的原因
  • 阅览C++文档不再困难
  • 熟悉现代C++的规划哲学

Streams I

实际上Streams库是C++中比较老的库了,但从Streams开始是有必要的,因为当你一开始学习C++,你的第一个项目很可能是一个HelloWorld程序,你很可能期望运用输入和输出流。
这节课会介绍一些流的细节

主要内容

  • overview + 字符串流(stringstream)
  • state bits
  • 输入/输出流

运用流的原因

咱们运用流的其中一个原因便是咱们期望咱们的程序能与外部的设备进行交互:当咱们编写程序时,不是所有咱们想运用的信息都包含在程序代码内的(self-contained)。
图里是咱们经常会用到的一些外部设备:

CS106L(现代C++):介绍/Streams:stringstream

控制台、键盘、文件这里不赘述。 这里提一下other programs:程序/进程之间传输数据,比方常用的IPC办法便是管道pipelines(注:pipelines完成的办法之一便是输入输出重定向)

网络中会用到sockets

比方说咱们想要读取一个文件中的浮点数3.14,咱们需求先读取这个浮点数信息的字符串表明:"3.14",再将其转化成浮点数3.14

CS106L(现代C++):介绍/Streams:stringstream

还有字符串到目标/结构体的转化:

CS106L(现代C++):介绍/Streams:stringstream
这里的关键便是你在将你程序内的某些变量、数据结构传输到控制台/socket之前,你需求将其转化成字符串。
这里面有两个难点:

  1. 怎么从外部源中以字符串的方式读取/写入数据

    CS106L(现代C++):介绍/Streams:stringstream

  2. 怎么将字符串方式的数据转化成咱们需求的类型

    CS106L(现代C++):介绍/Streams:stringstream
    stream做的事情便是将第一个问题做了笼统封装,当你运用流时你不用考虑stream库到底是怎么从外部设备中读取或写入数据的,你能够把stream想象成一个character buffer

CS106L(现代C++):介绍/Streams:stringstream

当你用cout这个输出流的时候,你不需求考虑cout是怎么与console进行交互的。

流的种类

每种流都是有一个输入流,一个输出流的:

CS106L(现代C++):介绍/Streams:stringstream

输出流:向buffer中刺进数据 stream <<
输入流:从buffer中提取数据 stream >>

stringstream

字符串流是没有与任何外部设备链接的流

CS106L(现代C++):介绍/Streams:stringstream

这是件功德,因为咱们现在能够只专注于类型转化是怎么做的。

ostringstream

ostringstream: output string stream,输出流是你将信息写入输出流/你能够发送数据给输出流。 当咱们构建一个ostringstream时,咱们能够给他一个字符串用于初始化。

#include <sstream> // stringstream
#include <iostream> // cin cout
using namespace std;
int main(){
    ostringstream oss("Ito En Green Tea");
    cout << oss.str() << endl;
}

常用的办法是str(),这个办法会获取oss中的整个数组然后将其转化成字符串

CS106L(现代C++):介绍/Streams:stringstream

【编译指令】

g++ -std=c++17 -Wall ostringstream.cpp -o oss

-Wall是翻开正告(Warn all,但实际上不是全部正告,能够再加上-Wextra等),-o是给可执行文件一个指定的姓名。
咱们也能够向ostringstream中写入信息,这便是为什么他叫output字符串流。

ostringstream oss("Ito En Green Tea");
cout << oss.str() << endl;
oss << 16.9 << " Ounce";
cout << oss.str() << endl;

考虑一下会打印的信息是什么?

CS106L(现代C++):介绍/Streams:stringstream
CS106L(现代C++):介绍/Streams:stringstream

为什么输出是这样的?原因是当你创建一个oss目标翻开一个流时,流的指针指向开始方位,之后当你向oss里写入数据时,指针从开始方位开始移动,他就会覆盖掉之前初始化的内容。
(留意这里的" Ounce"并不是string类的目标,它实际上是一个C string)

CS106L(现代C++):介绍/Streams:stringstream

假如你期望在翻开一个流时指针不是在开始方位,而是指定指针的偏移,你能够在创建流时结构函数内添加额外的参数:

  • ostringstream oss("Ito En Green Tea",ostringstream::ate): ate指at end,流翻开时就会指向最后面,此时的输出为:
    (注:另一个常见的参数是:stringstream::binary,表明字符串流为二进制形式)
    CS106L(现代C++):介绍/Streams:stringstream

第一节的视频只有一半,剩余的PPT里的内容我根据C++ Primer进行弥补


又找到了20年的视频,我会再根据视频弥补一些

istringstream

ostringstream oss("Ito En Green Tea");
oss << 16.9 << " Ounce";
istringstream iss(oss.str());
string output;
iss >> output;
cout << output << endl;

上面的代码只会输出16.9,假如输入流中下一个字符为空白字符,输入流就会中止读取,持续读取时会越过所有的前导空格。

CS106L(现代C++):介绍/Streams:stringstream
考虑下面的代码:

istringstream iss("16.9 Ounces");
int amount;
string unit;
iss >> amount;
iss >> unit;
cout << amount/2 << "-" << unit << endl;

amount的值是16,因为当流读到下一个字符是.,不能够解析成int类型时,就会中止解析。 unit的值是".9",因为当流读到下一个字符为空白字符就会中止读取。

CS106L(现代C++):介绍/Streams:stringstream

可读也可写的字符串流

stringstream可读可写,运用办法与istringstreamostringstream类似,能够去google一下

手动调整流的方位

手动调整流方位涉及到三种接口/类:

  1. 获取当时流方位的办法:oss.tellpiss.tellg,留意输出流和输入流的办法不一样
  2. 创建流方位偏移:streamoff(n)
  3. 设置流方位:oss.seekp(pos)iss.seekg(pos)
    示例:
    ostringstream oss("Ito En Green Tea");
    oss << 16.9;
    streampos pos = oss.tellp() + streamoff(3);
    oss.seekp(pos);
    oss << "Black";
    cout << oss.str() << endl;

输出:

CS106L(现代C++):介绍/Streams:stringstream

另一种写法:

    ostringstream oss("Ito En Green Tea");
    oss << 16.9;
    oss.seekp(streamoff(3),stringstream::cur);
    oss << "Black";
    cout << oss.str() << endl;

stringstream::cur表明当时流方位。

stringstream常用办法总结

  1. 参数为初始字符串的结构函数:istringstream iss("Initial");,ostringstream oss("Initial");
    结构函数运行添加“modes”来设置流方位(ate)和二进制形式(与文本形式对应)
  2. 向流buffer中刺进/获取数据的操作符oss << variss >> var,留意,操作符会进行变量类型与字符串类型之间彼此的转化
  3. 调整流方位的办法:
    1. 获取方位: oss.tellp()iss.tellg()
    2. 设置方位: oss.seekp(pos)iss.seekg(pos)
    3. 创建偏移: streamoff(n) 常用于相对于当时方位的偏移

流的链式<<、>>调用

CS106L(现代C++):介绍/Streams:stringstream

>>是能够链式调用的,var1和var2的值都会被转化成字符格局,然后刺进到oss的buffer中,那这种链式调用是怎么做到的呢?
实际上,>><<运算符会返回stream目标自身,因而在他的返回值上能够再次调用运算符。(趁便问一下我们这个运算符我们都怎么称呼?管道运算符?移位运算符?输入输出运算符?)

TODO:stringbuffer

能够访问和修改流内部的buffer,CS106L没有讲,之后我自己弥补一下。