C++流类库简介
C++为了克服C语言中的scanf
和printf
存在的缺点。,使用cin/cout
控制输入/输出。
cin
:表示标准输入的istream
类对象,cin
从终端读入数据。cout
:表示标准输出的ostream
类对象,cout
向终端写数据。cerr
:表示标准错误输出(非缓冲方式),导出程序错误信息。clog
:表示标准错误输出(缓冲方式),导出程序错误信息。
为了在程序中使用cin/cout
,必须在程序中包含iostream
库的相关头文件,格式为:#include <iostream>
iostream
类同时从istream
(输入流)和ostream
(输出流)类派生出来,允许双向输入/输出。输入由重载的>>
运算符完成,输出由重载的<<
运算符完成,输入/输出格式为:cin>>变量名
/cout<<变量名
。
除了用户端的输入/输出,C++还提供了文件的输入/输出类:
ifstream
:从istream
派生而来,把文件绑定到程序上输入。ofstream
:从ostream
派生而来,把文件绑定到程序上输出。fstream
:从iostream
派生而来,把文件绑定到程序上输入/输出。
使用iostream
库的文件流,必须包含相关的头文件:#include <fstream>
常用的流类库层次结构如图所示:
ios
类作为流类库的基类,主要派生了istream、ostream
类,由这两个类又派生了很多使用的流类,除ifstream
类、ofstream
类、iostream
类外,还有strstream
(输入/输出串流类)、istrstream
(输入串流类)、ostrstream
(输出串流类)等。下面将对这些流类的作用及用法分别进行介绍。
输入流/输出流格式
基本输出流
C++的ostream
提供了丰富的格式化和误格式化的输出功能:用流插入运算符输出标准数据类型;put
库成员函数输出字符;以八进制、十进制、十六进制数的形式输出数据;以各种精确方式输出浮点型数据;以科学计数法定点输出数据等。
流输出考研用流插入运算符,即重载的<<
(左移位)运算符来完成。<<
运算符左边的操作数时istream
类的一个对象(如cout
),右边可以是C++的合法表达式。
C++还提供了指针预定义输出运算符,允许输出项为显示对象的地址。在默认情况下,地址以十六进制的形式显示。
基本输入流
对应于输出,C++提供了实用的输入功能。类似于输出流中的流插入运算符,输入中引入了流读取运算符,也称为提取运算符。
流输入可以用流读取运算符,即重载的>>
(右移位)运算符来完成。类似于<<
运算符,流读取运算符是双目运算符,左边的操作数是istream
类的一个对象(如cin
),右边的操作数是系统定义的任何数据类型的变量
注意:1. >>
运算符也支持级联输入。在默认情况下,>>
运算符会跳过空格,读入后面与变量类型相应的值。因此,给一组变量输入值时,要用空格或换行符将输入的数值间隔开。
2. 当输入字符串时,>>
运算符会跳过空格,读入后面的非空格符,直到遇到另外一个空格才结束,并在字符串末尾自动放置字符\0
作为结束标志。
3. 输入数据时,不仅检查数据间的空格,还要进行类型检查、自动匹配
格式化输入/输出
在很多情况下,用户希望自己控制输出格式。C++提供了两种格式控制方法:用ios
类成员函数控制格式和用操纵符控制格式。
1. ios
类成员函数控制格式
在ios
类中,格式控制函数主要是通过对状态标志字、域宽、填充字及其精度来完成的。输入/输出格式由一个long int
型的状态标志字确定。在ios
类中public
部分进行了枚举,见下表:
状态标志 | 作用 |
---|---|
skipws | 跳过输入中的空白 |
left | 左对齐格式输出 |
right | 右对齐格式输出 |
internal | 在符号位和数值之间填入字符 |
dec | 十进制数显示 |
oct | 八进制数显示 |
hex | 十六进制数显示 |
showbase | 产生前缀,指示数值的进制基数 |
showpoint | 总是显示小数 |
uppercase | 十六进制数显示0X ,科学计数法显示E |
showpos | 在非负数中显示“+ ” |
boolalpha | 把true 和false 表示为字符串 |
scientific | 以科学记数法形式显示浮点数 |
fixed | 以小数形式显示浮点数 |
unitbuf | 输出操作后立即刷新所有流 |
stdio | 输出操作后刷新stdout 和stderr |
- 设置状态标志
设置状态标志可使用long ios::setf(long flags)
函数,格式为:stream_obj.setf(ios::enum_type);
说明:其中,stream_obj
为被影响的流对象,常用的是cin
和cout
。enum_type
为上表中列举的值。要想设置多个状态,彼此间用运算符“|
”连接(不能连接相反的格式控制符)。 - 清除状态标志
清除状态标志可使用long ios::unsetf(long flags)
,格式为:stream_obj.unsetf(ios::enum_type);
使用方法和ios::setf()
相同。 - 取状态标志
取状态标志用flags()
,在ios
类中重载了两个版本,格式为:long ios::flags();
或long ios::flags(long flag);
前者用于返回当前状态标志字;后者将状态标志字存储在flag
内。需要注意的是,与setf()
设置状态标志字不同,flags()
是取状态标志字的。 - 设置域宽
域宽用于控制输出格式,在ios
类中重载了两个函数控制域宽,原型为:int ios::width();
或者int ios::width(int w);
第一个函数得到当前的域宽了第二个函数用来设置新的域宽,并返回原来的域宽。需要注意的是,所设置的域宽仅仅对下一个输出的操作有效,当完成一次输出操作后,域宽又恢复为0
。 - 设置填充字符
填充字符的作用是,当输出值不满域宽时用设定的字符来填充,默认填充的字符为空字符。实际应用中填充字符函数与设置域宽函数配合使用,否则无空可填,毫无意义。ios
类提供了两个重载的成员函数来操作填充字符,原型为:char ios::fill();
或者char ios::fill(char c);
第一个函数返回当前使用的填充字符;第二个函数设置新的填充字符,并返回设置前的填充字符。 - 设置显示精度
类似地,ios
类也提供了重载的两个函数来显示精度,原型为:int ios::precision();
或者int ios::precision(int num);
第一个函数返回当前数值精度值;第二个函数设置新的显示精度,并返回设置前的精度。
2.操纵符控制格式
使用ios
类成员函数控制输入/输出格式,必须靠流对象来调用,而且不能直接嵌入输入/输出语句中,使用不够方便。C++提供了另外一种控制格式的方法,称为操纵符(控制符)方法,类似于函数的运算符。使用操纵符方法可以嵌入输入/输出语句中。
所有不带参数的操纵符定义在头文件iosream.h
中,带形参的操纵符定义在头文件iomanip.h
中,使用操纵符时需要包含相应的头文件。
提供的操纵符如下便:
标志 | 作 用 |
---|---|
ws | 在输入时跳过开头的空白符,仅用于输入 |
endl | 换行并刷输出流,仅用于输出 |
ends | 插入一个空字符,仅用于输出 |
flush | 刷新一个输出流,仅用于输出 |
skipws | 在输入时跳过输入中的空白符,仅用于输入 |
noskipws | 在输入时不跳过输入中的空白符,仅用于输入 |
internal | 将填充字符加到符号和数值之间 |
dec | 十进制数显示,可用于输入/输出 |
oct | 八进制数显示,可用于输入/输出 |
hex | 十六进制数显示,可用于输入/输出 |
showbase | 产生前缀,指示数值的进制基数 |
noshowbase | 不产生基数前缀 |
showpoint | 总是显示小数 |
noshowpoint | 只有当小数存在时显示小数 |
uppercase | 十六进制数显示0X ,科学计数法显示E |
nouppercase | 十六进制数显示0x ,科学计数法显示e |
showpos | 在非负数中显示“+ ” |
noshowpos | 在非负数中不显示“+ ” |
boolalpha | 把true 和false 表示为字符串 |
noboolalpha | 把true 和false 表示为1和0 |
scientific | 以科学记数法形式显示浮点数 |
fixed | 以小数形式显示浮点数 |
setfill(ch) | 用ch 填充空白字符 |
setprecision(n) | 将浮点数精度设置为n |
setw(w) | 按照w 个字符来读或写数值 |
setbase(b) | 以进制基数b 来输出整数值 |
setiosflags(n) | 设置有n 指定的格式标志 |
resetiosflags(n) | 清除有n 指定的格式标志 |
用户自定义的操纵符控制格式
在C++中,除系统提供的预定义操纵符之外,还允许用户定义操纵符,便于控制一些频繁使用的格式操作,使格式控制更加方便。
自定义输出流操纵符算子函数格式为:ostream &自定义输出操纵符算子函数名(ostream& stream){return stream;}
自定义输入流操纵符算子函数格式为:istream &自定义输出操纵符算子函数名(istream& stream){return stream;}
其他输入/输出函数
get()
和put()
get(char& ch)
从输入流中提取一个字符,包括空白字符,并把它存储在ch
中,返回被应用的istream
对象。此函数在类istream
里。
对应于get()
,类ostream
提供了put(char ch)
,用于输出字符。
gei()
的重载版本:get(char *str, streamsize size,char delimiter='\n');
其中str
代表一个字符数组,用来存放被读取的字符。size
代表可以从istream
中读入字符的最大数目。delimiter
代表如果遇到它就要结束读取字符的动作,delimiter
本身不会被读入,而是留在istream
中,作为istream
的下一个字符。常见的一个错误是,执行第二个get()
时省略delimiter
。getline()
使用get()
输入字符串时,经常忘记去掉delimiter
所以引入函数getline()
,其原型和get()
的重载一样:getline(char *str, streamsize size,char delimiter='\n');
使用getline()
比get()
方便,它除去了delimiter
,而不是将其留作下一个字符。write()
和read()
ostream
类成员函数write()
提供一种输出字符数组的方法。它不是输出“直到终止字符为止”,而是输出某个长度的字符序列,包括空字符。函数原型如下:write(char *str, streamsize size);
其中str
是要输出的字符数组,length
是要显示的字符个数。write()
返回当前被调用的ostream
类对象。
与ostream
类的write()
对应的是istream
类的read()
,原型如下:read(char *str, streamsize size);
read()
从输入流中读取size
个连续的字符,并将其放在地址从str
开始的内存中。gcount()
返回由最会一个read()
调用所读取的字节数,而read()
返回当前被调用的istream
类对象。
用户自定义类型的输入/输出
当实现一个类的类型时,有时需要这个类支持输入和输出的操作,以便可以将类对象嵌入输入或输出流中。对于用户自定义的数据类型的输入/输出,可以通过重载>>
运算符和<<
运算符实现。
重载输出运算符
输出运算符<<
,又称为流插入运算符。定义其重载函数的格式为:
ostream &operator<<(ostream &out, class_name &obj)
{out << obj.data1;out << obj.data2;```return out;
}
函数中第一个参数out
是对ostream
对象的引用,即out
必须是输出流对象;第二个参数是用户自定义要输出的类对象的引用。
<<
运算符不能作为类的成员函数,只能作为友元函数(要访问类的私有成员)来实现。
重载输入运算符
输入运算符>>
,又称为流提取运算符。定义其重载函数的格式为:
istream &operator<<(istream &in, class_name &obj)
{in >> obj.data1;in >> obj.data2;```return in;
}
函数中第一个参数in
是对istream
对象的引用,即in
必须是输入流对象;第二个参数是用户自定义要输入的类对象的引用。
与<<
运算符类似,>>
运算符也不能作为类的成员函数,只能作为类的友元函数或独立函数。
例如:>>
运算符和<<
运算符重载
#include <iostream>
#include <string>
using namespace std;
class Word
{char* word;size_t iNum;//存储字符个数
public:Word(const char* const str = NULL);virtual ~Word(){if (word)delete[]word;}friend ostream& operator <<(ostream& out, const Word& obj);friend istream& operator >>(istream& in, Word& obj);
};Word::Word(const char* const str)
{if (str != NULL){iNum = strlen(str);word = new char[iNum + 1];strcpy_s(word, iNum + 1, str);}
}ostream& operator<<(ostream& out,const Word& obj)
{out << "<" << obj.iNum << ">" << obj.word << endl;return out;
}istream& operator>>(istream& in, Word& obj)
{char str[100];in.getline(str, 100);if (in.gcount() > 0){delete[]obj.word;obj.iNum = strlen(str);obj.word = new char[obj.iNum + 1];strcpy_s(obj.word, obj.iNum + 1, str);}return in;
}int main()
{Word word("hello");cout << word;cin >> word;cout << word;return 0;
}
程序运行结果为:
<5>hello
W
<1>W