C++流类库简介

C++为了克服C语言中的scanfprintf存在的缺点。,使用cin/cout控制输入/输出。

  1. cin:表示标准输入的istream类对象,cin从终端读入数据。
  2. cout:表示标准输出的ostream类对象,cout向终端写数据。
  3. cerr:表示标准错误输出(非缓冲方式),导出程序错误信息。
  4. clog:表示标准错误输出(缓冲方式),导出程序错误信息。

为了在程序中使用cin/cout,必须在程序中包含iostream库的相关头文件,格式为:#include <iostream>
iostream类同时从istream(输入流)和ostream(输出流)类派生出来,允许双向输入/输出。输入由重载的>>运算符完成,输出由重载的<<运算符完成,输入/输出格式为:cin>>变量名/cout<<变量名
除了用户端的输入/输出,C++还提供了文件的输入/输出类:

  1. ifstream:从istream派生而来,把文件绑定到程序上输入。
  2. ofstream:从ostream派生而来,把文件绑定到程序上输出。
  3. fstream:从iostream派生而来,把文件绑定到程序上输入/输出。

使用iostream库的文件流,必须包含相关的头文件:#include <fstream>
常用的流类库层次结构如图所示:
C++:输入流/输出流-LMLPHP

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部分进行了枚举,见下表:

  1. 设置状态标志
    设置状态标志可使用long ios::setf(long flags)函数,格式为:stream_obj.setf(ios::enum_type);
    说明:其中,stream_obj为被影响的流对象,常用的是cincoutenum_type为上表中列举的值。要想设置多个状态,彼此间用运算符“|”连接(不能连接相反的格式控制符)。
  2. 清除状态标志
    清除状态标志可使用long ios::unsetf(long flags),格式为:stream_obj.unsetf(ios::enum_type);使用方法和ios::setf()相同。
  3. 取状态标志
    取状态标志用flags(),在ios类中重载了两个版本,格式为:long ios::flags();long ios::flags(long flag);前者用于返回当前状态标志字;后者将状态标志字存储在flag内。需要注意的是,与setf()设置状态标志字不同,flags()是取状态标志字的。
  4. 设置域宽
    域宽用于控制输出格式,在ios类中重载了两个函数控制域宽,原型为:int ios::width();或者 int ios::width(int w);第一个函数得到当前的域宽了第二个函数用来设置新的域宽,并返回原来的域宽。需要注意的是,所设置的域宽仅仅对下一个输出的操作有效,当完成一次输出操作后,域宽又恢复为0
  5. 设置填充字符
    填充字符的作用是,当输出值不满域宽时用设定的字符来填充,默认填充的字符为空字符。实际应用中填充字符函数与设置域宽函数配合使用,否则无空可填,毫无意义。ios类提供了两个重载的成员函数来操作填充字符,原型为:char ios::fill();或者char ios::fill(char c);第一个函数返回当前使用的填充字符;第二个函数设置新的填充字符,并返回设置前的填充字符。
  6. 设置显示精度
    类似地,ios类也提供了重载的两个函数来显示精度,原型为:int ios::precision();或者int ios::precision(int num);第一个函数返回当前数值精度值;第二个函数设置新的显示精度,并返回设置前的精度。

2.操纵符控制格式

使用ios类成员函数控制输入/输出格式,必须靠流对象来调用,而且不能直接嵌入输入/输出语句中,使用不够方便。C++提供了另外一种控制格式的方法,称为操纵符(控制符)方法,类似于函数的运算符。使用操纵符方法可以嵌入输入/输出语句中。
所有不带参数的操纵符定义在头文件iosream.h中,带形参的操纵符定义在头文件iomanip.h中,使用操纵符时需要包含相应的头文件。
提供的操纵符如下便:

用户自定义的操纵符控制格式

在C++中,除系统提供的预定义操纵符之外,还允许用户定义操纵符,便于控制一些频繁使用的格式操作,使格式控制更加方便。
自定义输出流操纵符算子函数格式为:ostream &自定义输出操纵符算子函数名(ostream& stream){return stream;}
自定义输入流操纵符算子函数格式为:istream &自定义输出操纵符算子函数名(istream& stream){return stream;}

其他输入/输出函数

  1. 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
  2. getline()
    使用get()输入字符串时,经常忘记去掉delimiter所以引入函数getline(),其原型和get()的重载一样:getline(char *str, streamsize size,char delimiter='\n');
    使用getline()get()方便,它除去了delimiter,而不是将其留作下一个字符。
  3. 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
02-03 13:57