C++基础教程面向对象(学习笔记(103))

本文详细介绍了C++中ostream类的各种输出格式化方法,包括使用标志和操纵器改变输出格式,如数字基底、精度、对齐方式等。

使用ostream和ios输出

在本节中,我们将介绍iostream输出类(ostream)的各个方面。

注意:本课程中的所有I / O功能都位于std命名空间中。这意味着所有I / O对象和函数都必须以“std ::”为前缀,或者必须使用“using namespace std;”语句。

插入操作符

插入运算符(<<)用于将信息放入输出流。C ++为所有内置数据类型预定义了插入操作,您已经了解了如何为自己的类重载插入操作符。

在关于流的课程中,您看到istream和ostream都来自一个名为ios的类。ios(和ios_base)的一个工作是控制输出的格式化选项。

格式化

有两种方法可以更改格式选项:标志和操纵器。您可以将标志视为可以打开和关闭的布尔变量。 操纵器是放置在流中的对象,它影响输入和输出的方式。

要打开标志,请使用setf()函数,并将相应的标志作为参数。例如,默认情况下,C ++不会在正数前面打印+号。但是,通过使用std :: showpos标志,我们可以更改此行为:

std::cout.setf(std::showpos); // 打开std :: showpos标志
std::cout << 27 << '\n';

这导致以下输出:

+27
可以使用OR(|)运算符一次打开多个ios标志:

std::cout.setf(std::showpos | std::uppercase); //打开std :: showpos和std :: uppercase标志
std::cout << 27 << '\n';

要关闭标志,请使用unsetf()函数:

std::cout.setf(std::showpos); //打开std :: showpos标志
std::cout << 27 << '\n';
std::cout.unsetf(std::showpos); //关闭std :: showpos标志
std::cout << 28 << '\n';

这导致以下输出:

+27
28
当使用需要提及的setf()时,还有一点棘手。许多标志属于组,称为格式组。格式组是一组执行类似的(有时相互排斥)格式化选项标志。例如,名为“basefield”的格式组包含标志“oct”,“dec”和“hex”,它们控制整数值的基数。默认情况下,设置“dec”标志。因此,如果我们这样做:

std::cout.setf(std::hex); // 尝试打开十六进制输出
std::cout << 27 << '\n';

我们得到以下输出:

27
它没用!原因是因为setf()只打开了标志 - 它不够聪明,无法关闭互斥标志。因此,当我们打开std :: hex时,std :: dec仍然打开,并且std :: dec显然优先。有两种方法可以解决这个问题。

首先,我们可以关闭std :: dec,以便只设置std :: hex:

std::cout.unsetf(std::dec); //关闭十进制输出
std::cout.setf(std::hex); // 打开十六进制输出
std::cout << 27 << '\n';

现在我们按预期获得输出:

1b
第二种方法是使用另一种形式的setf(),它接受两个参数:第一个参数是要设置的标志,第二个参数是它所属的格式化组。使用这种形式的setf()时,属于该组的所有标志都将被关闭,并且只有传入的标志才会打开。例如:

// 打开std :: hex作为唯一的std :: basefield标志
std::cout.setf(std::hex, std::basefield);
std::cout << 27 << '\n';

这也产生了预期的输出:

1b
使用setf()和unsetf()往往很尴尬,因此C ++提供了另一种更改格式选项的方法:操纵器。关于操纵器的好处是它们足够聪明,可以打开和关闭相应的标志。以下是使用一些操纵器来更改基础的示例:

std::cout << std::hex << 27 << '\n'; // 以十六进制打印27
std::cout << 28 << '\n'; // 我们还是十六进制
std::cout << std::dec << 29 << '\n'; // 回到小数

该程序产生输出:

1b
1c
29
通常,使用操纵器比设置和取消设置标志要容易得多。通过标志和操纵器可以获得许多选项(例如更改基础),但是,其他选项只能通过标记或操纵器获得,因此了解如何使用它们非常重要。

有用的格式化程序

这是一些更有用的标志,操纵器和成员函数的列表。标志存在于ios类中,操纵符存在于std命名空间中,成员函数存在于ostream类中。

GroupFlag含义
boolalpha如果设置,则布尔值打印“true”或“false”。如果未设置,则布尔值打印0或1
Manipulator含义
boolalpha布尔打印“真实”或“虚假”
noboolalpha布尔值打印0或1(默认)

例:

std::cout << true << " " << false << '\n';
 
std::cout.setf(std::boolalpha);
std::cout << true << " " << false << '\n';
 
std::cout << noboolalpha << true << " " << false << '\n';
 
std::cout << boolalpha << true << " " << false << '\n';

结果:

1 0
true false
1 0
true false

GroupFlag含义
showpos如果设置,则使用+前缀正数
Manipulator含义
showpos使用+前缀正数
noshowpos不使用+前缀正数

例:

std::cout << 5 << '\n';
 
std::cout.setf(std::showpos);
std::cout << 5 << '\n';
 
std::cout << noshowpos << 5 << '\n';
 
std::cout << showpos << 5 << '\n';

结果:

5
+5
5
+5

GroupFlag含义
大写如果设置,则使用大写字母
Manipulator含义
大写使用大写字母
小写使用小写字母

例:

std::cout << 12345678.9 << '\n';
 
std::cout.setf(std::uppercase);
std::cout << 12345678.9 << '\n';
 
std::cout << nouppercase << 12345678.9 << '\n';
 
std::cout << uppercase << 12345678.9 << '\n';

结果:

1.23457e + 007
1.23457E + 007
1.23457e + 007
1.23457E + 007

GroupFlag含义
basefielddec以十进制打印值(默认)
basefieldhex以十六进制打印值
basefieldoct以八进制打印值
basefield(none)根据值的前导字符打印值
Manipulator含义
dec以十进制打印值
hex以十六进制打印值
oct以八进制打印值

例:

std::cout << 27 << '\n';
 
std::cout.setf(std::dec, std::basefield);
std::cout << 27 << '\n';
 
std::cout.setf(std::oct, std::basefield);
std::cout << 27 << '\n';
 
std::cout.setf(std::hex, std::basefield);
std::cout << 27 << '\n';
 
std::cout << std::dec << 27 << '\n';
std::cout << std::oct << 27 << '\n';
std::cout << std::hex << 27 << '\n';

结果:

27
27
33
1b
27
33
1b
到现在为止,您应该能够看到通过标志和操纵器设置格式之间的关系。在将来的示例中,我们将使用操纵器,除非它们不可用。

精度,符号和小数点

使用操纵器(或标志),可以更改显示浮点数的精度和格式。有几种格式化选项以复杂的方式组合,因此我们将仔细研究这一点。

GroupFlag含义
floatfieldfixed对浮点数使用十进制表示法
floatfieldscientific对浮点数使用科学记数法
floatfield(none)固定用于少数位的数字,否则为科学
floatfieldshowpoint始终显示小数点,并为浮点值尾随0
Manipulator含义
fixed对值使用十进制表示法
scientific使用科学记数法表示值
showpoint显示小数点,并为浮点值尾随0
noshowpoint对于浮点值,不显示小数点和尾随0
setprecision(int)设置浮点数的精度(在iomanip.h中定义)
成员函数含义
precision()返回浮点数的当前精度
sprecision(int)使设置浮点数的精度并返回旧精度

如果使用固定或科学记数法,精度将确定显示分数中的小数位数。请注意,如果精度小于有效位数,则数字将被舍入。

std::cout << std::fixed << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';
 
std::cout << std::scientific << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

产生结果:

123.456
123.4560
123.45600
123.456000
123.4560000

1.235e + 002
1.2346e + 002
1.23456e + 002
1.234560e + 002
1.2345600e + 002
如果既不使用固定也不科学,精度确定应显示多少有效数字。同样,如果精度小于有效位数,则数字将被舍入。

std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

产生以下结果:

123
123.5
123.46
123.456
123.456
使用showpoint操纵器或标志,可以使流写入小数点并尾随零。

std::cout << std::showpoint << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

产生以下结果:

123。
123.5
123.46
123.456
123.4560
这是一个包含更多示例的汇总表:
在这里插入图片描述
宽度,填充字符和对齐方式

通常,当您打印数字时,会打印数字而不考虑它们周围的空间。但是,可以向左或向右对齐数字的打印。为此,我们必须首先定义一个字段宽度,它定义一个值将具有的输出空间的数量。如果打印的实际数字小于字段宽度,则将左对齐或右对齐(如指定的那样)。如果实际数字大于字段宽度,则不会被截断 - 它将溢出字段。

GroupFlag含义
adjustfieldinternal左对齐数字的符号,并对该值进行右对齐
adjustfieldleft以左对齐符号和值
adjustfieldright右对齐符号和值(默认)
Manipulator含义
internal左对齐数字的符号,并对该值进行右对齐
left左对齐符号和值
right右对齐符号和值(默认)
setfill(char)将参数设置为填充字符(在iomanip.h中定义)
setw(int)将输入和输出的字段宽度设置为参数(在iomanip.h中定义)
成员函数含义
fill()返回当前填充字符
fill(char)设置填充字符并返回旧填充字符
width()返回当前字段宽度
width(int)设置当前字段宽度并返回旧字段宽度

为了使用任何这些格式化程序,我们首先必须设置字段宽度。这可以通过width(int)成员函数或setw()操纵器来完成。请注意,右对齐是默认值。

std::cout << -12345 << '\n'; //打印默认值,没有字段宽度
std::cout << std::setw(10) << -12345 << '\n'; // 打印默认字段宽度
std::cout << std::setw(10) << left << -12345 << '\n'; // 打印左对齐
std::cout << std::setw(10) << right << -12345 << '\n'; // 打印右对齐
std::cout << std::setw(10) << internal << -12345 << '\n'; // 打印内部合理

这会产生结果:

-12345
-12345
-12345
-12345

  • 12345
    需要注意的一点是setw()和width()只影响下一个输出语句。它们不像其他标志/操纵器那样持久。

现在,让我们设置一个填充字符并执行相同的示例:

std::cout.fill('*');
std::cout << -12345 << '\n'; // print default value with no field width
std::cout << std::setw(10) << -12345 << '\n'; // print default with field width
std::cout << std::setw(10) << left << -12345 << '\n'; // print left justified
std::cout << std::setw(10) << right << -12345 << '\n'; // print right justified
std::cout << std::setw(10) << internal << -12345 << '\n'; // print internally justified

这会产生输出:

-12345
**** - 12345
-12345 ****
**** - 12345

  • **** 12345
    请注意,字段中的所有空格都填充了填充字符。

ostream类和iostream库包含其他可能有用的输出函数,标志和操作符,具体取决于您需要执行的操作。与istream类一样,这些主题更适合专注于标准库的教程或书籍(例如Nicolai M. Josuttis出版的优秀书籍“The C ++ Standard Template Library”)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值