本节将详细探讨 <iostream> 输出类 ostream 的各项功能。
插入运算符(<<)
插入运算符(<<)用于向输出流写入数据。C++ 对所有内置类型均已预定义插入操作,也允许为自定义类重载该运算符。
在前面的课程中,你已看到 istream 与 ostream 均派生自 ios。ios(以及 ios_base)的职责之一便是控制输出的格式选项。
格式设置
修改格式有两种途径:标志位(flags) 与 操控符(manipulators)。
- 标志位可视为布尔开关,通过 setf()/unsetf()进行开/关。
- 操控符是插入流中的对象,用于影响输入/输出的格式。
示例:默认情况下,正数前不输出 + 号;使用 std::ios::showpos 可改变此行为:
std::cout.setf(std::ios::showpos); // 打开 showpos 标志
std::cout << 27 << '\n';           // 输出 +27
可用按位或(|)同时打开多个标志:
std::cout.setf(std::ios::showpos | std::ios::uppercase);
std::cout << 1234567.89f << '\n';  // 输出 +1.23457E+06
关闭标志使用 unsetf():
std::cout.setf(std::ios::showpos);
std::cout << 27 << '\n';
std::cout.unsetf(std::ios::showpos);
std::cout << 28 << '\n';
// 输出:
// +27
// 28
格式组(format groups)的注意事项
某些标志属于同一格式组,彼此互斥。例如,basefield 组包含 dec、hex、oct,默认启用 dec:
std::cout.setf(std::ios::hex); // 仅打开 hex,但未关闭 dec
std::cout << 27 << '\n';       // 仍输出 27(未生效)
解决方法:
- 手动关闭冲突标志:
std::cout.unsetf(std::ios::dec);
std::cout.setf(std::ios::hex);
std::cout << 27 << '\n';       // 输出 1b
- 使用双参数 setf():传入欲设置标志及其所属格式组,组内其他标志自动关闭:
std::cout.setf(std::ios::hex, std::ios::basefield);
std::cout << 27 << '\n';       // 输出 1b
操控符(manipulators)
使用操控符通常比手动开关标志更方便。例如:
std::cout << std::hex << 27 << '\n'; // 十六进制输出
std::cout << 28 << '\n';             // 仍在十六进制
std::cout << std::dec << 29 << '\n'; // 恢复十进制
// 输出:
// 1b
// 1c
// 29
常用格式控制一览
下表列出常用标志、操控符及成员函数。标志位于 std::ios;操控符位于 std 命名空间;成员函数位于 std::ostream。
| 分组 | 标志 | 含义 | 
|---|---|---|
| — | std::ios::boolalpha | 布尔值输出 true/false;否则输出0/1 | 
| 操控符 | 含义 | |
| — | — | |
| std::boolalpha/std::noboolalpha | 切换布尔文本/数字输出 | 
示例:
std::cout << true << ' ' << false << '\n';      // 1 0
std::cout.setf(std::ios::boolalpha);
std::cout << true << ' ' << false << '\n';      // true false
std::cout << std::noboolalpha << true << ' ' << false << '\n'; // 1 0
| 分组 | 标志 | 含义 | 
|---|---|---|
| — | std::ios::showpos | 正数前显示 + | 
| 操控符 | 含义 | |
| — | — | |
| std::showpos/std::noshowpos | 切换正数前是否显示 + | 
示例:
std::cout << 5 << '\n';        // 5
std::cout.setf(std::ios::showpos);
std::cout << 5 << '\n';        // +5
std::cout << std::noshowpos << 5 << '\n'; // 5
| 分组 | 标志 | 含义 | 
|---|---|---|
| — | std::ios::uppercase | 十六进制/科学计数法使用大写字母 | 
| 操控符 | 含义 | |
| — | — | |
| std::uppercase/std::nouppercase | 切换大小写 | 
示例:
std::cout << 12345678.9 << '\n';          // 1.23457e+007
std::cout.setf(std::ios::uppercase);
std::cout << 12345678.9 << '\n';          // 1.23457E+007
| 分组 | 标志 | 含义 | 
|---|---|---|
| std::ios::basefield | std::ios::dec | 十进制(默认) | 
| std::ios::hex | 十六进制 | |
| std::ios::oct | 八进制 | |
| 操控符 | 含义 | |
| — | — | |
| std::dec/std::hex/std::oct | 切换进制 | 
示例:
std::cout << 27 << '\n';                    // 27
std::cout << std::hex << 27 << '\n';        // 1b
std::cout << std::oct << 27 << '\n';        // 33
精度、计数法与小数点
通过操控符或标志可控制浮点数的显示精度与格式。
| 分组 | 标志 | 含义 | 
|---|---|---|
| std::ios::floatfield | std::ios::fixed | 定点表示 | 
| std::ios::scientific | 科学计数法 | |
| std::ios::showpoint | 始终显示小数点及尾随零 | |
| 操控符 | 含义 | |
| — | — | |
| std::fixed/std::scientific | 切换定点/科学计数法 | |
| std::showpoint/std::noshowpoint | 切换是否强制显示小数点 | |
| std::setprecision(int) | 设置浮点精度(位于 <iomanip>) | 
示例:
std::cout << std::fixed << std::setprecision(3) << 123.456 << '\n'; // 123.456
std::cout << std::scientific << std::setprecision(3) << 123.456 << '\n'; // 1.235e+002
若未指定 fixed/scientific,精度指有效数字位数:
std::cout << std::setprecision(3) << 123.456 << '\n'; // 123
使用 showpoint 强制显示小数点:
std::cout << std::showpoint << std::setprecision(3) << 123.456 << '\n'; // 123.
宽度、填充字符与对齐
默认输出时数字周围不留空格。可通过设置字段宽度并指定对齐方式实现左/右/内部对齐。
| 分组 | 标志 | 含义 | 
|---|---|---|
| std::ios::adjustfield | std::ios::internal | 符号左对齐,数值右对齐 | 
| std::ios::left | 整体左对齐 | |
| std::ios::right | 整体右对齐(默认) | |
| 操控符 | 含义 | |
| — | — | |
| std::internal/std::left/std::right | 切换对齐方式 | |
| std::setfill(char) | 设置填充字符(位于 <iomanip>) | |
| std::setw(int) | 设置字段宽度(位于 <iomanip>) | 
示例:
std::cout << std::setw(10) << -12345 << '\n';         // 默认右对齐
std::cout << std::setw(10) << std::left << -12345 << '\n'; // 左对齐
std::cout << std::setw(10) << std::internal << -12345 << '\n'; // 内部对齐
输出:
    -12345
-12345    
-    12345
注意:setw() 与 width() 仅影响下一次输出,不具持久性。
设置填充字符:
std::cout.fill('*');
std::cout << std::setw(10) << std::left << -12345 << '\n'; // -12345****
ostream 及整个 <iostream> 库还包含更多输出函数、标志与操控符,视需求可进一步查阅标准库文档。
