原书这一章写得太拉垮,我实在看不下去,所以我决定重写一版。
这个库值得拿出来单独写篇文章,是因为这个基本上是每个学c++的人最先接触的标准库。每一个hello world程序里都要用一个cout。在学c++的初期,以及程序不工作的时候我们都想快速的加个debug语句,用iostream基本上都是必不可少的。
我相信大家都知道怎么用cin和cout,可我的问题来了:你能不能解释清楚语句
cout << "hello world!" << endl; 是怎么工作的?
这个语句封装的非常好,所以对于刚开始学c++的人来说,搞清楚这个并不是那么容易。让我来一点一点把这个内容讲清楚。
基本结构
我们先来看看iostream这整个库里有些什么抽象类,整个库的结构大概如下:

这里我对每个类进行简单的解释:
base_ios:这是整个 IOStream 类的最顶层基类,负责处理流的底层细节,比如错误状态标志(good, fail, bad, eof)和格式化标志。ios从它继承,但通常我们不直接使用它。ios:继承自base_ios,它管理流的格式化信息和状态。你可以把它看作是所有输入输出流的共同“父亲”。它不直接处理读写操作,而是提供一个通用的框架。istream:这是一个抽象的输入流基类。它定义了所有输入操作的行为,比如用于读取数据的operator>>、get()和getline()。cin就是这个类的实例,它连接到标准输入设备(通常是键盘)。ostream:这是一个抽象的输出流基类。它定义了所有输出操作的行为,比如用于写入数据的operator<<和put()。cout就是这个类的实例,它连接到标准输出设备(通常是屏幕)。iostream:继承自istream和ostream。它同时具备输入和输出的能力,所以可以进行双向读写。你可以把iostream理解为一个同时能读能写的接口。
非常注意这里的
iostream和#include <iostream>不是一个东西。是一个头文件,里边包含了这个库所有的类,而上述的iostream是一个有双向读写功能的抽象类。
在这些抽象类的基础上,我们有了平时常用的 cin , cout, fstream , sstream 。如下图:

这里我们可以看到:
cin 是一个 istream ,所以它只有输入功能
cout 是一个 ostream , 所以它只有输出功能
fstream 和sstream 都是 iostream , 所以他们既可以输入,也可以输出。
工作原理
整个库的核心思想:流 (Stream)
流是一个抽象概念,它代表一个字节序列。你可以从流中读取数据(输入流),也可以向流中写入数据(输出流)。
这个抽象的好处在于,你的代码不需要关心数据的具体来源或目的地。无论是从键盘读取、向屏幕打印,还是读写文件,你都使用同样的操作符 >>(提取)和 <<(插入),这让代码变得非常统一和优雅。
在这一整套的实现中,istream和ostream干了一件超级厉害的事,叫做运算符重载(operator overloading),他们把位移运算符>>和 << 改写了功能,然后返回了 *this ,这个操作类似于设计模式里的builder pattern,这样可以把所有的操作全部串起来。
还有一点需要解释,cin 和cout 是两个提前创建好的全局对象(global object)所以我们在调用的时候并没有重新建一个新的实例,而是直接用。
和 cin ,cout 类似,我们还有 cerr 和clog,这些都是提前定义好的全局对象,所以他们被统称为标准流对象 (Standard Stream Objects)
解释开始的问题
现在我们就可以很容易的解释我刚开始提出的问题:cout << "hello world!" << endl; 是怎么工作的?
首先,我们先调用了全局变量cout ,
然后用了它在 ostream 里重载的 << ,这个东西把后边的字符串"hello world!" 传到cout 里,在这个类里把他显示到了屏幕上,之后继续返回同样一个cout 实例,
然后对endl 进行同样的操作。
实例
解释清楚了基本概念,我来给几个常用流的例子
标准流对象
需要包含 <iostream> 头文件。
std::cin: Console Input。标准输入流,通常关联到键盘。std::cout: Console Output。标准输出流,通常关联到屏幕。它是有缓冲的,意味着数据可能不会立即显示,而是等缓冲区满了或遇到特定条件(如std::endl)再输出。std::cerr: Console Error。标准错误流,通常也关联到屏幕。它没有缓冲,意味着你写入的数据会立即显示。主要用于输出错误信息。std::clog: Console Log。标准日志流,也用于输出错误信息。与cerr不同,clog有缓冲。
#include <iostream>
#include <string>
int main() {
std::string name;
int age;
std::cout << "你好,请输入你的名字:";
std::cin >> name; // 从键盘读取一个单词到 name
std::cout << "请输入你的年龄:";
std::cin >> age; // 从键盘读取一个整数到 age
std::cout << "欢迎, " << name << "!你 " << age << " 岁了。" << std::endl;
// 假设发生了一个错误
std::cerr << "这是一个错误信息!" << std::endl;
return 0;
}
文件流 (File Streams) - <fstream>
需要包含 <fstream> 头文件。
std::ifstream: Input File Stream,用于从文件中读取数据。std::ofstream: Output File Stream,用于向文件中写入数据。std::fstream: File Stream,既可以读文件,也可以写文件。
示例代码:
#include <iostream>
#include <fstream>
#include <string>
int main() {
// 写入文件
std::ofstream outFile("user.txt");
if (outFile.is_open()) {
outFile << "Alice\n";
outFile << 30 << std::endl;
outFile.close(); // 关闭文件
std::cout << "数据已写入 user.txt" << std::endl;
}
// 从文件读取
std::ifstream inFile("user.txt");
if (inFile.is_open()) {
std::string name;
int age;
inFile >> name >> age; // 像使用 cin 一样读取
std::cout << "从文件中读到: " << "姓名=" << name << ", 年龄=" << age << std::endl;
inFile.close();
}
return 0;
}
b. 字符串流 (String Streams) - <sstream>
需要包含 <sstream> 头文件。这是一种在内存中操作的流,它把一个 std::string 对象当作流来处理。非常适合用于数据格式转换。
std::istringstream: Input String Stream,从一个 string 中读取数据。std::ostringstream: Output String Stream,向一个 string 中写入数据。std::stringstream: String Stream,既可读也可写。
示例代码:
#include <iostream>
#include <sstream>
#include <string>
int main() {
// 场景1: 将多种数据类型拼接成一个字符串
std::ostringstream oss;
std::string name = "Bob";
int age = 25;
double score = 95.5;
oss << "姓名: " << name << ", 年龄: " << age << ", 分数: " << score;
std::string result = oss.str(); // 从 ostringstream 获取拼接好的字符串
std::cout << result << std::endl; // 输出: 姓名: Bob, 年龄: 25, 分数: 95.5
// 场景2: 从一个字符串中解析数据
std::string data = "Charlie 40 88.0";
std::istringstream iss(data);
std::string parsed_name;
int parsed_age;
double parsed_score;
iss >> parsed_name >> parsed_age >> parsed_score; // 像使用 cin 一样解析
std::cout << "解析结果: " << parsed_name << " " << parsed_age << " " << parsed_score << std::endl;
return 0;
}
这个库里还有格式化标志 (Formatting flags)和流操作符(stream manipulators),我会在之后发布的文章里介绍他们。
3288

被折叠的 条评论
为什么被折叠?



