C++ day43 C++ I/O (二) 深入剖析cout对象

本文主要介绍cout对象的很多方法,这些方法是机器重要的,是cout可以完成输出任务的关键秘诀。

文章目录

  • 把数值类型转换为字符流(文本格式)
    • 重载插入运算符:把值转换为文本格式
      • 14个内置数据类型都有重载版本
      • 字符指针类型也有重载版本
      • 示例:用```void *```打印字符串的地址
      • 拼接输出:非常好的设计特性!因为返回值类型都是```ostream &```
    • put():用于显示字符;现为模板函数;也可以拼接输出
    • write():用于显示整个字符串
      • 示例
      • 给write()传入数值,它会逐字节解释为ascii码(神奇)
    • 刷新输出缓冲区:endl控制符,flush控制符
      • 示例:输出到屏幕不需要等缓冲区满才刷新
      • 控制符的本质是函数
    • 用cout格式化输出:使用ios_base类的成员函数来控制字段宽度和小数位数等格式状态
      • 示例:先看看cout的默认格式
      • 修改显示整数的计数系统:控制符dec, hex, oct(十进制,十六进制,八进制)
        • 示例
      • 调整字段宽度:对齐;width()成员方法
        • 示例:默认右对齐,用空格填满左边空位
        • 示例:用fill()成员函数改变填充字符
      • 设置浮点数的显示精度,precision()成员函数
        • 示例:默认模式
          • 显示小数点和末尾的0:ios_base类的setf()函数,ios_base类的静态常量showpoint
      • setf():调整标记位的另一种途径
        • ios_base类的其他格式常量
          • 示例:setf()的第一个原型
          • 示例:setf()的第二个原型
    • 标准控制符:对用户最友好的格式化方法,可替代setf()方法
      • 头文件iomanip:提供了除了标准控制符外的其他控制符,用于设置字段宽度,精度,填充字符等
        • 示例:非常好!美观
  • 总结

把数值类型转换为字符流(文本格式)

重载插入运算符:把值转换为文本格式

insertion operator

  • 所有重载版本的返回值类型都是ostream &

  • <<默认含义是按位左移运算符。但是由于他长得像信息流动,所以就被ostream类发现了,并把它重载了,他就获得了一份新工作,一个新角色。

14个内置数据类型都有重载版本

并且ostream类重载的非常详细,<<可以识别到C++的所有基本数据类型(14个,11个整型,3个浮点型),即C++给这些数据类型的每一个都提供了一个重载版本。
C++ day43 C++ I/O (二) 深入剖析cout对象_第1张图片

比如:

cout << 34;//ostream & operator<<(int);

把14中内置基本类型的值都可以转换为文本形式,比如把-2.45转换为5个字符,’-’, ‘2’, ‘.’, ‘4’, ‘5’

字符指针类型也有重载版本

C++ day43 C++ I/O (二) 深入剖析cout对象_第2张图片
char数组名,显式char指针,用引号括起来的C字符串都是字符串指针,因为C++就是用字符串指针来表示字符串的。

除了字符串指针之外的指针,C++就认为是void *,就会打印地址,即指针变量中存的值,而不是打印字符串了。

如果你不想打印字符串,而是想打印出字符串的地址,那就强制转换为void *就好啦。

示例:用void *打印字符串的地址

#include 

int main()
{
    using std::cout;
    using std::endl;

    int eggs = 12;
    char * amount = "dozen";
    cout << &eggs << endl;//打印地址
    cout << amount << endl;//打印字符串
    cout << (void *) amount << endl;//打印地址
    return 0;
}
0x6efef8
dozen
0x4ba025

拼接输出:非常好的设计特性!因为返回值类型都是ostream &

插入运算符的重载版本返回的都是调用他们的对象
在这里插入图片描述
C++ day43 C++ I/O (二) 深入剖析cout对象_第3张图片

put():用于显示字符;现为模板函数;也可以拼接输出

  • 是ostream类的成员方法,所以cout对象可以调用
  • 最开始的原型:
ostream & put(char);

后来为了用于wchar_t, 把他变成了模板函数,即参数可以是char,可以是wchar_t.

  • 拼接输出:
cout.put('i').put('t');

write():用于显示整个字符串

basic_ostream<charT, traits> & write(const char_type * s, streamsize n);//第一个参数是字符串的地址,第二个参数是要显示的字符的数目

示例

#include 
#include 

int main()
{
    using std::cout;
    using std::endl;

	const char * state1 = "Florida";
	const char * state2 = "Kansas";
	const char * state3 = "Euphoria";

	int len = std::strlen(state2);
	cout << "Increasing loop index:\n";
	int i;
	for (i=1;i<=len;++i){
		cout.write(state2, i);
		cout << endl;
	}

	cout << "Decreasing loop index:\n";

	for (i=len;i>=1;--i){
		cout.write(state2, i);
		cout << endl;
	}

	cout.write(state2, len + 10) << endl;

    return 0;
}

state1, state3两个字符串只是为了便于观察长度超出state2的长度时会显示什么。

这几个C字符串都存在一起的诶,地址连着的。

Increasing loop index:
K
Ka
Kan
Kans
Kansa
Kansas
Decreasing loop index:
Kansas
Kansa
Kans
Kan
Ka
K
Kansas Euphoria
  • 我又试了试超出的多一点:
cout.write(state2, len + 20) << endl;

输出是:

Kansas Euphoria     Index

可以看到,内存中有啥就输出啥了

  • 注意,write方法也可以和插入运算符拼接:
cout.write(state2, len + 10) << endl;

给write()传入数值,它会逐字节解释为ascii码(神奇)

#include 

int main()
{
	long val = 560031841;
	cout.write((char *) &val, sizeof(long));
    return 0;
}
aha!
Process returned 0 (0x0)   execution time : 0.575 s
Press any key to continue.

560031841转换为32二进制是(我的计算机上,long占4个字节):

00100001 01100001 01101000 01100001

分别转换为是十进制,对应于:33 97 104 97

把他们当做ascii码,倒着看就是aha!

刷新输出缓冲区:endl控制符,flush控制符

控制符 manipulator

之前说过了,C++使用缓冲区来匹配不同的传输速率,但是如果输出不是输出到文件,而是输出到屏幕,则其实速率差别并不大,而且我们也绝对不想等到缓冲区的512字节都满了,才全部一起显示到屏幕呀,毕竟我们需要看输出的信息。

所以输出到屏幕的话,刷新输出缓冲区的条件不是缓冲区满,而是使用控制符,C++定义了两个控制符用来强行刷新缓冲区,即把缓冲区的所有数据转移到屏幕:flush和endl。

  • flush控制符:刷新缓冲区
  • endl控制符:刷新缓冲区并插入一个换行符

其实大多数场景都是希望在输入即将发生时输出缓冲区,因为一般输入都需要提前输出对应的输入提示信息。

示例:输出到屏幕不需要等缓冲区满才刷新

#include 
#include 

int main()
{
    using std::cout;
    using std::endl;

	cout << "Hello good-looking! " << std::flush;
	cout << "Wait just a moment, please." << endl;
	cout << "Hello good-looking! " << std::flush;
    return 0;
}
Hello good-looking! Wait just a moment, please.
Hello good-looking!

控制符的本质是函数

cout << flush;//相当于flush(cout);

这是因为ostream类对<<进行了重载,当参数为函数对象时,就调用这个函数并把cout作为参数。

用cout格式化输出:使用ios_base类的成员函数来控制字段宽度和小数位数等格式状态

ostream是ios_base类的间接基类(ios_base是ios类的基类,ios类是ostream类的基类),所以ostream类的对象cout可以使用ios_base类的方法。

示例:先看看cout的默认格式

#include 

int main()
{
    using std::cout;

	cout << "12345678901234567890\n";
	char ch = 't';
	int t = 123;
	cout << ch << ":\n";
	cout << t << ":\n";
	cout << -t << ":\n";

	double f1 = 1.200;
	cout << f1 << ":\n";
	cout << (f1+1.0/9.0) << ":\n";

	double f2 = 1.57e2;
	cout << f2 << ":\n";
	f2 += 1.0/9.0;
	cout << f2 << ":\n";
	cout << (f2*1.0e4) << ":\n";

	double f3 = 2.3e-4;
	cout << f3 << ":\n";
	cout << f3/10 << ":\n";

    return 0;
}

加个冒号是为了看字段宽度的。

可以看到,1.200末尾的0没有被显示。这是因为,C++默认不显示浮点数结尾的0

12345678901234567890
t:
123:
-123:
1.2:
1.31111:
157:
157.111:
1.57111e+006:
0.00023:
2.3e-005:

修改显示整数的计数系统:控制符dec, hex, oct(十进制,十六进制,八进制)

//设置cout对象的计数系统格式状态为十六进制,即以十六进制来打印整数
hex(cout);//相当于cout << hex;

和刚才的flush一样,控制符是函数。但是注意,不是成员函数哈。

示例
#include 

int main()
{
    using std::cout;

	int n = 15;
	cout << n << ' ' << n*n << " decimal\n";

	//十六进制
	cout << std::hex;
	cout << n << ' ' << n*n << " hexadecimal\n";

	//八进制
	cout << std::oct << n << ' ' << n*n << " octal\n";

	//回到十进制
	dec(cout);
	cout << n << ' ' << n*n << " decimal\n";
    return 0;
}
15 225 decimal
f e1 hexadecimal
17 341 octal
15 225 decimal

调整字段宽度:对齐;width()成员方法

C++ day43 C++ I/O (二) 深入剖析cout对象_第4张图片

字段宽度是指一个字符串的最大长度,如果设置为10, 则就只能显示最多10个字符,但是如果字符串多于10个字符,C++当然不会给你截短,只显示前10个字符,没那么僵硬,而是会自动增长字段长度,然后完整的显示字符串。

示例:默认右对齐,用空格填满左边空位
#include 

int main()
{
    using std::cout;

	int w = cout.width(30);
	cout << "default field width = " << w << ":\n";
	cout.width(5);
	cout << "N" << ":\n";
	cout << "N * N" << ":\n";
	for (long i=1;i<=100;i *= 10){
		cout.width(5);
		cout << i << ':';
	    cout.width(8);
		cout << i*i << ":\n";
	}
    return 0;
}
  • 默认字段宽度竟然是0?????是的!!!

这是因为C++会增长字段,以完整地容纳数据

  • 字段都是默认右对齐的,左边用空格填充。

用来填充的字符叫做填充字符,fill character, 这里是空格。

        default field width = 0:
    N:
N * N:
    1:       1:
   10:     100:
  100:   10000:

如果想要左对齐,可以用left控制符

#include 

int main()
{
    using std::cout;
    cout << std::left;
	int w = cout.width(30);
	cout << "default field width = " << w << ":\n";
	cout.width(5);
	cout << "N" << ":\n";
	cout << "N * N" << ":\n";
	for (long i=1;i<=100;i *= 10){
		cout.width(5);
		cout << i << ':';
	    cout.width(8);
		cout << i*i << ":\n";
	}
    return 0;
}
default field width =         0:
N    :
N * N:
1    :1       :
10   :100     :
100  :10000   :
示例:用fill()成员函数改变填充字符

但是fill()不同于width(), 它一旦设置了,就一直有效。

#include 

int main()
{
    using std::cout;

	int w = cout.width(30);
	cout.fill('-');
	cout << "default field width = " << w << ":\n";
	cout.width(5);
	cout << "N" << ":\n";
	cout << "N * N" << ":\n";
	for (long i=1;i<=100;i *= 10){
		cout.width(5);
		cout << i << ':';
	    cout.width(8);
		cout << i*i << ":\n";
	}
    return 0;
}
--------default field width = 0:
----N:
N * N:
----1:-------1:
---10:-----100:
--100:---10000:

设置浮点数的显示精度,precision()成员函数

  • 和fill()一样,一旦设置,一直有效。
  • C++的默认精度是6
  • 浮点数有三种输出模式:定点模式,科学模式,默认模式。精度的具体含义取决于输出模式,如果在默认模式,则精度指的是显示的总位数;而科学模式和定点模式中,精度指的是小数点后面的位数

在这里插入图片描述

示例:默认模式
#include 

int main()
{
    using std::cout;

	float price1 = 20.40;
	float price2 = 1.9 + 8.0/9.0;
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

	cout.precision(2);
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

    return 0;
}

可以看到,第三行连小数点都不显示了,因为只让显示2位。这里的截短不是C++做的,是程序员自己要截短的,怪不着C++,C++没有私自背地里偷摸摸的给截短。

"Furry Friends" is $20.4!
"Fiery Friends" is $2.78889!
"Furry Friends" is $20!
"Fiery Friends" is $2.8!

要怎么进入科学输出模式和定点输出模式呢??

——使用控制符fixed和scientific!

定点模式

#include 

int main()
{
    using std::cout;


	float price1 = 20.40;
	float price2 = 1.9 + 8.0/9.0;

	cout << std::fixed;//定点输出模式
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

	cout.precision(2);
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

    return 0;
}
"Furry Friends" is $20.400000!
"Fiery Friends" is $2.788889!
"Furry Friends" is $20.40!
"Fiery Friends" is $2.79!

科学模式:

#include 

int main()
{
    using std::cout;

	float price1 = 20.40;
	float price2 = 1.9 + 8.0/9.0;

	cout << std::scientific;//定点输出模式
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

	cout.precision(2);
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

    return 0;
}
"Furry Friends" is $2.040000e+001!
"Fiery Friends" is $2.788889e+000!
"Furry Friends" is $2.04e+001!
"Fiery Friends" is $2.79e+000!
显示小数点和末尾的0:ios_base类的setf()函数,ios_base类的静态常量showpoint

从上面的示例可以看到,C++默认是不会显示末尾的0,如果精度太少,则也不会显示小数点。

但是有时候,比如显示账目,把小数点和0都显示出来更加美观。但是iostream类没有提供相关方法,ios_base类提供了。

注意showpoint是ios_base类的类级静态常量,即其具有类作用域,所以如果在类的成员方法外面用它,则要用作用域运算符说明ios_base类。

#include 

int main()
{
    using std::cout;
    using std::ios_base;

	float price1 = 20.40;
	float price2 = 1.9 + 8.0/9.0;

	cout.setf(ios_base::showpoint);//显示小数点,且显示末尾0
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

	cout.precision(2);
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

    return 0;
}

20已经占用了2位,所以小数点显示了就不会再显示后面的了。而且可以看到,小数点并没有占精度位。

"Furry Friends" is $20.4000!
"Fiery Friends" is $2.78889!
"Furry Friends" is $20.!
"Fiery Friends" is $2.8!

setf():调整标记位的另一种途径

setf()是ios_base类的一个成员函数

ios_base类的其他格式常量

ios_base类有一个受保护的数据成员,它的每一位,都表示和控制着输出格式化的一个方面。比如有3个bit表示计数系统,hex,dec, oct。

除了上面展示的用控制符来改变输出格式状态外,还可以用setf()方法。

setf()有两种重载版本
第一种:

fmtflags setf(fmtflags);//用于设置单个位控制的格式信息,返回的是设置之前的信息

fmtflags是bitmask类的typedef名称,用来存储格式标记,在ios_base类中定义。bitmask类的关键思想是每一位都可以单独访问,且都有自己的含义。iostream包使用bitmask来存储状态信息。bitmask类型可以是整型,枚举或者STL的bitset容器。

fmtflags常量已经被ios_base类定义了, 我们不需要记住数字,直接传入这些常量就好啦,但是要知道他们实际上就是bitmask类型的值哦,即fmtflags的值。

C++ day43 C++ I/O (二) 深入剖析cout对象_第5张图片

示例:setf()的第一个原型
#include 

int main()
{
    using std::cout;
    using std::endl;
    using std::ios_base;

    int temperature = 63;
    cout << "Today's water temperature:";
    cout.setf(ios_base::showpos);//在十进制正数前面显示+符号
    cout << temperature << endl;

    cout << "For our programming friends, that's ";
    cout << std::hex << temperature << endl;
    cout.setf(ios_base::uppercase);//对16禁进制输出,用大写字母(只针对16进制)
    cout.setf(ios_base::showbase);//显示基数前缀0x
    cout << "or\n";
    cout << temperature << endl;
    cout << "How " << true << "! oops -- How ";
    cout.setf(ios_base::boolalpha);//显示true或者false
    cout << true << "!\n";

    return 0;
}
Today's water temperature:+63
For our programming friends, that's
3f
or
0X3F
How 0X1! oops -- How true!

学到的点:

  • showpos只适用于十进制,因为C++把八进制和十六进制都当做是无符号的,所以没有给十六进制的正数前面显示+
  • uppercase只适用于十六进制,因为8进制和10进制都没有字母。
示例:setf()的第二个原型
fmtflags setf(fmtflags, fmtflags);//返回的也是设置之前的信息

第一个参数用来表示要设置哪些位(比如floatfield则设置科学位和定点位这两个比特,其他位置完全不影响),和第一个原型的那个参数的功能一样;第二个参数用来表示要清除哪些位,比如你要把进制从十进制改为16进制,则要把hex那一位改为1,还要把dec那一位改为0呀。

而且由于ios_base类已经定义好了常量,就特别方便。
C++ day43 C++ I/O (二) 深入剖析cout对象_第6张图片
左对齐:把值放在字段的左端。
内部对齐:把符号或者基数前缀放在字段左端,而数字放在字段右边。

示例

#include 
#include 

int main()
{
    using std::cout;
    using std::endl;
    using std::ios_base;

    cout.setf(ios_base::left, ios_base::adjustfield);//左对齐left justification
    cout.setf(ios_base::showpos);//显示正数前面的符号
    cout.setf(ios_base::showpoint);//显示小数点
    cout.precision(3);

    //使用科学模式
    ios_base::fmtflags old = cout.setf(ios_base::scientific, ios_base::floatfield);//存住旧的存储格式
    long n;
    cout << "左对齐\n";
    for (n=1;n<=41;n+=10){
        cout.width(4);
        cout << n << "|";
        cout.width(12);
        cout << sqrt(double(n)) << " \n";
    }
    cout.setf(ios_base::internal, ios_base::adjustfield);
    cout.setf(old, ios_base::floatfield);
    cout << "内部对齐\n";
    for (n=1;n<=41;n+=10){
        cout.width(4);
        cout << n << "|";
        cout.width(12);
        cout << sqrt(double(n)) << "|\n";
    }
    cout << "右对齐\n";
    cout.setf(ios_base::right, ios_base::adjustfield);
    cout.setf(ios_base::fixed, ios_base::floatfield);
    for (n=1;n<=41;n+=10){
        cout.width(4);
        cout << n << "|";
        cout.width(12);
        cout << sqrt(double(n)) << "|\n";
    }

    return 0;
}
左对齐
+1  |+1.000e+000
+11 |+3.317e+000
+21 |+4.583e+000
+31 |+5.568e+000
+41 |+6.403e+000
内部对齐
+  1|+       1.00|
+ 11|+       3.32|
+ 21|+       4.58|
+ 31|+       5.57|
+ 41|+       6.40|
右对齐
  +1|      +1.000|
 +11|      +3.317|
 +21|      +4.583|
 +31|      +5.568|
 +41|      +6.403|

学到的点:

  • 科学输出模式的指数位数随实现而异,这里是三位。
  • 没有默认模式的一个标记位。只有科学位和定点位两位,只有科学位被设置则为科学模式,只有定点位被设置则为定点模式,否则(都没设置或者都设置)则为默认模式。

可以用下面这句代码设置为默认模式,注意要强制转换,不然会报错,说不能把int转换为fmtflags类型:

 cout.setf((ios_base::fmtflags)0, ios_base::floatfield);//第一个参数表示不设置任何位(科学位和定点位都不设置)
#include 
#include 

int main()
{
    using std::cout;
    using std::endl;
    using std::ios_base;

    cout.setf(ios_base::left, ios_base::adjustfield);//左对齐left justification
    cout.setf(ios_base::showpos);//显示正数前面的符号
    cout.setf(ios_base::showpoint);//显示小数点
    cout.precision(3);

    //使用科学模式
    ios_base::fmtflags old = cout.setf(ios_base::scientific, ios_base::floatfield);//存住旧的存储格式
    long n;
    cout << "左对齐(科学模式)\n";
    for (n=1;n<=41;n+=10){
        cout.width(4);
        cout << n << "|";
        cout.width(12);
        cout << sqrt(double(n)) << " \n";
    }
    cout.setf(ios_base::internal, ios_base::adjustfield);
    cout.setf(old, ios_base::floatfield);
    cout << "内部对齐(默认模式)\n";
    for (n=1;n<=41;n+=10){
        cout.width(4);
        cout << n << "|";
        cout.width(12);
        cout << sqrt(double(n)) << "|\n";
    }
    cout << "右对齐(定点模式)\n";
    cout.setf(ios_base::right, ios_base::adjustfield);
    cout.setf(ios_base::fixed, ios_base::floatfield);
    for (n=1;n<=41;n+=10){
        cout.width(4);
        cout << n << "|";
        cout.width(12);
        cout << sqrt(double(n)) << "|\n";
    }
    //使用默认模式
    cout << "右对齐(默认模式)\n";
    cout.setf((ios_base::fmtflags)0, ios_base::floatfield);
    for (n=1;n<=41;n+=10){
        cout.width(4);
        cout << n << "|";
        cout.width(12);
        cout << sqrt(double(n)) << "|\n";
    }

    return 0;
}
左对齐(科学模式)
+1  |+1.000e+000
+11 |+3.317e+000
+21 |+4.583e+000
+31 |+5.568e+000
+41 |+6.403e+000
内部对齐(默认模式)
+  1|+       1.00|
+ 11|+       3.32|
+ 21|+       4.58|
+ 31|+       5.57|
+ 41|+       6.40|
右对齐(定点模式)
  +1|      +1.000|
 +11|      +3.317|
 +21|      +4.583|
 +31|      +5.568|
 +41|      +6.403|
右对齐(默认模式)
  +1|       +1.00|
 +11|       +3.32|
 +21|       +4.58|
 +31|       +5.57|
 +41|       +6.40|
  • 可以用unsetf()方法撤销刚才setf()的设置,原型:
    在这里插入图片描述

示例:

#include 

int main()
{
    using std::cout;
    using std::ios_base;

	float price1 = 20.40;
	float price2 = 1.9 + 8.0/9.0;

	cout.setf(ios_base::showpoint);//显示小数点,且显示末尾0
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

	cout.precision(2);
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

	cout.unsetf(ios_base::showpoint);
	cout.precision(2);
	cout << "\"Furry Friends\" is $" << price1 << "!\n";
	cout << "\"Fiery Friends\" is $" << price2 << "!\n";

    return 0;
}
"Furry Friends" is $20.4000!
"Fiery Friends" is $2.78889!
"Furry Friends" is $20.!
"Fiery Friends" is $2.8!
"Furry Friends" is $20!
"Fiery Friends" is $2.8!

另一个示例:

#include 

int main()
{
    using std::cout;
    using std::endl;
    using std::ios_base;

    int temperature = 63;
    cout << "Today's water temperature:";
    cout.setf(ios_base::showpos);//在十进制正数前面显示+符号
    cout << temperature << endl;

    cout << "For our programming friends, that's ";
    cout << std::hex << temperature << endl;
    cout.setf(ios_base::uppercase);//对16禁进制输出,用大写字母(只针对16进制)
    cout.setf(ios_base::showbase);//显示基数前缀0x
    cout << "or\n";
    cout << temperature << endl;
    cout << "How " << true << "! oops -- How ";
    cout.setf(ios_base::boolalpha);//显示true或者false
    cout << true << "!\n";
    cout.unsetf(ios_base::boolalpha);//不显示true或者false
    cout << true << "!\n";

    return 0;
}
Today's water temperature:+63
For our programming friends, that's 3f
or
0X3F
How 0X1! oops -- How true!
0X1!
  • 无论cout现在处于哪种模式unsetf(ios_base::field);都会切换回默认模式

标准控制符:对用户最友好的格式化方法,可替代setf()方法

setf()成员方法可以设置格式,但是需要提供各种常量参数,不是很方便,C++为了用户控制格式更方便,就提供了很多控制符。比如dec, hex, oct

cout << dec << left << fixed;//使用十进制计数,显示左对齐,定点模式输出浮点数

其他的控制符还有:
C++ day43 C++ I/O (二) 深入剖析cout对象_第7张图片
C++ day43 C++ I/O (二) 深入剖析cout对象_第8张图片

这张表的右边是用setf()或者unsetf()方法,可以看到使用控制符真的方便很多,打字都少了好多。

这都要归功于重载的插入运算符哇。

头文件iomanip:提供了除了标准控制符外的其他控制符,用于设置字段宽度,精度,填充字符等

io manipulator 输入输出控制符

前面的标准控制符不能设置字段宽度,所以iomanip头文件又加了一些控制符,但是这些控制符和标准控制符不一样,=他们带参数,但是他们不是成员函数,仍然是控制符,所以还是用插入运算符使用它们!!

  • setprecision():设置精度,接受一个指定精度的整数参数
  • setfill():接受一个指定填充字符的char参数
  • setw():接受一个指定字段宽度的整数参数
示例:非常好!美观
#include 
#include 
#include 

int main(){
    using namespace std;
    cout << fixed << right;
    cout << setw(6) << "N" << setw(14) << "square root"
         << setw(15) << "fourth root\n";

    double root;
    for (int n=10;n<=100;n+=10){
        root = sqrt(double(n));
        cout << setw(6) << setfill('.') << n << setfill(' ')
             << setw(12) << setprecision(3) << root
             << setw(14) << setprecision(4) << sqrt(root)
             << endl;
    }
    return 0;
}
     N   square root   fourth root
....10       3.162        1.7783
....20       4.472        2.1147
....30       5.477        2.3403
....40       6.325        2.5149
....50       7.071        2.6591
....60       7.746        2.7832
....70       8.367        2.8925
....80       8.944        2.9907
....90       9.487        3.0801
...100      10.000        3.1623

总结

  • cout最重要的功能就是类型转换,即把各种类型的数据全部转换为字符流,以放入输出流去显示。它的实现方法就是通过提供了一系列插入运算符的重载原型,每一个数据类型都有一个重载版本,比如cout << 1.25就会调用ostream & operator<<(double)原型,而这个函数的功能就是把double浮点数转换为文本,在这里就是转换为四个字符。
  • C++提供了很多控制符,比如hex,oct, dec, left, fixed,非常好用。
  • 只有width()一个函数需要不断设置,其他方法都是设置一次一直有效。
  • iomanip的控制符好好用,控制格式真的很棒

你可能感兴趣的:(C++)