C++语言中提供的标准库封装实现了常见的I/O操作功能。开发者通过包含头文件,就可以直接满足实现应用程序中需求。C++中提供类的好处就是开发者可以自行封装实现属于自身的I/O流操作,或者在使用时直接指定标准库中提供的相应接口操作。而开发者在应用程序中指定使用标准库提供的I/O操作可以极大提高软件编写的效率。
13.2.1 C++流类介绍
C++语言的I/O是采用流的形式实现的。通常采用字节流作为输入输出的传输载体进行传输,而传输的始发与目标地则是外围设备与计算机内存。I/O操作中对应着输入输出两种不同的操作。输入操作是从计算机设备比如键盘、硬盘等输入到计算机内存的过程,而输出操作则是将字节以字节流的方式从计算机内存输出到外部设备上。通常这类外部设备是显示设备或者打印设备等。
C++标准库的iostream库封装实现了上述I/O的两种不同流向操作。它提供了很多专门针对输入输出的接口操作。iostream库是针对I/O操作封装实现的一个类库,它包含了上百个I/O相关操作功能。在使用该库时,需要包含iostream库提供的头文件。由于iostream库是根据不同需求,而提供了多个类封装实现。那么,包含不同的头文件意味着在应用程序中可以使用相对应类提供的接口功能操作。
iostream类库提供的多种I/O类的封装实现,其层次结构如图13.1所示。
图13.1 C++ I/O操作类层次结构
在图13.1中,最顶层的为ios基类。该类中封装了C++输入/输出共同的基本操作方法。第二层继承ios基类,分别为istream类(提供流输入操作)、ostream类(提供流输出操作)。而随后的类iostream则继承了流输入操作类与流输出操作类,提供了流的输入/输出全操作。
应用程序中常用的输入输出的三个对象cout、cin与cerr分别为库预先定义的ostream类、istream类对象。其中,cerr则为ostream输出类的对象,主要用于输出标准错误;cout则为输出流对象主要用于向屏幕等设备输出对应的信息;cin对象则为输入流对象,主要用于从当前键盘等输入设备输入信息。另外,I/O类层次结构中类ifstream、ofstream以及fstream则是专门用于文件处理提供的输入输出操作。它们将会在后续文件处理章节详细讲述。下面小节将会讲述具体输入输出操作类的基本应用情况。
13.2.2 输出流操作
iostream类库中针对输出流操作专门提供了ostream类的实现。该类提供了相当丰富的输出功能操作,包括输出各种内置数据类型的数据以及相应的字符输出方法。另外,它还可以配合设置格式化的各类输出操作使用等。本小节只针对输出各种内置类型数据以及相应的字符输出作出演示讲解,更多的配合输出格式化等操作将会在流操纵算子小节介绍。
流的输出操作对象主要为cout与cerr。两个都为库中预先定义的ostream对象实例。通常在应用程序中流的输出对象会配合提供的<<运算符重载方法使用。下面通过一些输出对象操作实例的演示了解流的输出操作应用情况。
1.准备实例
打开UE编辑器,新建空白文件另存为chapter1306.cpp。随后连同makefile编译文件一起通过FTP工具传输至Linux服务器。客户端通过scrt访问操作。实例程序代码编辑如下所示。
/**
* 实例chapter1306
* 源文件chapter1306.cpp
* C++输出流操作
*/
#include <iostream>
using namespace std;
int main()
{
cout<<"welcometo study Linux of C++!"<<endl; //通过cout对象输出整条字符串
cout<<"welcometo " //分行输出连续的字符串
<<"studyLinux "
<<"ofC++! \n";
cout<<"welcometo "<<"study Linux "<<"ofC++!"<<endl; //分段输出连续的字符串
cout<<"expressioncompute:"; //输出流中输出表达式计算结果
cout<<(43+12)<<endl;
cout<<"expressioncompute:"<<(12+100)<<endl;
char*str = "hello"; //定义字符串指针,初始化字符串”hello”
cout<<"charstr:"<<str<<endl; //输出字符串指针指向值
cout.put('d'); //通过cout对象调用put方法,将字符d输出
//到屏幕
return0;
}
本实例主要通过标准输入输出流提供的操作对象,演示几种常见的输出流操作方法。程序主要在main函数内部实现,具体程序剖析见程序注释与后面讲解。
2.编辑makefile
Linux平台下需要编译源文件为chapter1306.cpp,相关makefile工程文件编译命令编辑如下所示。
OBJECTS=chapter1306.o
CC=g++
chapter1306: $(OBJECTS)
$(CC)$(OBJECTS) -g -o chapter1306
clean:
rm-f chapter1306 core $(OBJECTS)
submit:
cp-f -r chapter1306 ../bin
cp-f -r *.h ../include
上述makefile文件套用前面的模板格式,主要替换了代码文件、程序编译中间文件、可执行程序等。在编译命令部分-g选项的加入,表明程序编译同时加入了可调式信息。
3.编译运行程序
当前shell下执行make命令,生成可执行程序文件。随后,通过make submit命令提交程序文件至本实例bin目录,通过cd命令定位至实例bin目录,执行该程序文件运行结果如下所示。
[developer@localhost src]$ make
g++ -c -ochapter1306.o chapter1306.cpp
g++ chapter1306.o -g -o chapter1306
[developer @localhost src]$ make submit
cp -f -r chapter1306 ../bin
cp -f -r *.h ../include
[developer @localhost src]$ cd ../bin
[developer @localhost bin]$ ./chapter1306
welcome to study Linux of C++!
welcome to study Linux of C++!
welcome to study Linux of C++!
expression compute:55
expression compute:112
char str:hello
上述实例中首先演示了cout对象中流插入语句输出字符串应用。
第一行输出语句用于输出整体字符串“welcome to study Linux of C++!”,并且以endl表示换行操作。第二、三、四行语句中则用三条输出语句分行拼凑而成打印如上同一句字符串,最后直接以‘\n’字符表示结束换行。输出流重载的运算符同样可以在同一行语句中连续使用。例如,第五句则采用连续三个<<运算符输出整个同上的字符串。
流输出对象cout与重载的<<运算符结合操作中,也可以输出表达式计算结果。(缺少主语)不但可以用于单独输出表达式结果也可以使用多个<<运算符组合操作实现同样的功能。第六、七八行的语句主要用于演示表达式计算结果的输出应用。其中,第六、七句分句打印字符串与表达式计算结果。而第八句则将字符串与表达式计算结合成一行语句分两个<<运算符打印输出。其中,小括号将表达式两个操作数括起来,为了更清晰的表达运算符操作的执行顺序,避免运算符执行优先级引起歧义,而影响计算结果。
随后通过定义字符串指针并初始化为“hello”,之后通过cout对象与<<运算符结合运用打印输出字符串提示信息与对应的字符串指针指向的内存内容。最后通过ostream类对象cout调用其方法成员put向屏幕输出字符操作。该方法调用可以单个直接调用put(‘d’)向屏幕输出字符'd',也可以如最后一句代码中连续调用put()方法,该方法最后输出一个字符为'\n'用于换行。
13.2.3 输入流操作
iostream库中针对流的输入操作则通过类istream来提供。输入流是通过预先定义的输入类对象cin配合重载运算符>>实现的。重载实现的>>运算符会忽略输入流中的空白符、制表符等特殊符号,直接将当前输入的信息插入到输入流中去。下面通过几个小的代码片段演示基本输入流操作。
//代码片段一
stringstr; //定义字符串str
cout<<"Pleaseinput string value:"<<endl; //打印从键盘输入信息提示
cin>>str; //输入字符串
cout<<"Thestring's value:"<<str<<endl; //打印输出字符串信息
//代码片段二
intvalue1,value2; //定义两个整型变量value1与value2
cout<<"Pleaseinput two int data:"<<endl; //提示从键盘输入两个整型值信息
cin>>value1>>value2; //连续输入两个整型值
cout<<"expressioncompute:"<<(value1+value2)<<endl; //打印输出两个整型变量相加的表达式结果
//代码片段三
charch; //定义字符变量ch
cout<<"Pleaseinput a char:"<<endl; //提示从键盘输入字符信息
cin.get(ch); //输入流对象cin调用get方法,输入字符ch
cout.put(ch).put('\n'); //输出流对象cout调用put方法,打印输出ch字符值
//代码片段四
charbuffer[100]; //定义字符数组,拥有100个字符元素
cin.get(buffer,100); //输入流对象cin调用get方法,从键盘输入字符串
cout<<"Enterstring value:"<<buffer<<endl; //打印输出键盘输入的字符串值
//代码片段五
charbuffer[100]; //定义字符数组,拥有100个字符元素
cout<<"Pleaseinput a line string:"<<endl; //提示从键盘输入字符串
cin.getline(buffer,100); //输入流对象cin调用getline方法,从键盘输入字符串
cout<<"Entera line string value:"<<buffer<<endl; //打印输出键盘输入的字符串值
上述代码片段中主要演示了日常开发中输入流的几种应用。主要都用于实现从输入设备获取对应的信息插入到对应的输入流中。
q 代码片段一主要演示了字符串在输入流中的应用情况。首先定义一个空字符串实例对象,随后根据cout输出提示输入字符串信息。随后,使用cin对象与<<运算符结合输入字符串对象str。最后,通过cout输出流对象打印最终的字符串信息。
q 代码片段二则主要演示了两个整型数据表达式计算在输入流中的应用。代码中先定义两个整型数据变量value1与value2。随后,cout对象提示输入两个整型数据,而cin输入流对象配合>>运算符操作在输入流中插入两个整型数据,并存放于两个整型变量中。最后,cout对象则输出最终表达式计算结果。
q 代码片段三中则主要应用输入流类中提供的get方法来实现字符输入功能。代码首先定义字符变量ch,随后提示输入字符信息。随后,通过cin对象调用get(ch)方法等待从键盘输入字符。用户输入字符之后,get()方法将输入的字符存放到字符变量ch中。最后,使用cout对象调用put()方法输出该字符信息,并以连续调用的方式输出字符换行符'\n'。
q 代码片段四中则主要演示了get重载实现的方法。通过将输入信息存放于指定长度的字符数组中实现输入流操作。首先定义包含100个元素的字符数组buffer,随后通过cin对象调用get方法。根据传入的实参将输入的字符串信息存放于字符数组buffer中,最后打印输出该字符数组信息。
q 代码片段五则演示了getline()方法应用,具体代码片段实现思路和get()方法相同。与cin结合>>运算符实现的输入流操作不同,get()与getline()方法则不会忽略输入信息中的空格等特殊信息符等。对于从键盘输入的信息,通常会原样的在输出设备上显示。
13.2.4 流操纵算子
以上介绍的输出输入流操作主要是无格式的。C++语言还提供了多个操纵算子配合输入输出流对象,从而完成对应流的格式化操作。C++语言提供了相当丰富的与格式化相关的操作,如设置精度、格式化标志、字符填充等。由于提供的流操作算子内容相对较多,而篇幅有限,这里无法一一介绍。下面将会通过几个代码片段实例,演示并讲解流操作算子最常见的应用情形。
1.代码片段1
代码片段一主要演示了整型数在输出流中以不同进制的格式化输出。整型数在应用程序中输出时默认以十进制方式显示,特殊情况下也需要改变输出进制格式。C++提供了对应的操作算法改变输出整型数的基数。通常有三种方式dec、oct与hex,分别表示十进制、八进制以及十六进制操作算法。代码中,首先定义整型变量value,随后打印输入整型值的提示信息。从键盘设备输入整型数后,通过cout对象将整型变量通过对应的进制操作算法输出不同进制整型数。
//代码片段一
intvalue; //定义整型变量
cout<<"Pleaseinput a int value:"<<endl; //提示从键盘输入整型变量
cin>>value; //从键盘输入整型变量
cout<<"decvalue:"<<dec<<value<<endl; //输出十进制整型变量
cout<<"hexvalue:"<<hex<<value<<endl; //输出十六进制整型变量
cout<<"octvalue:"<<oct<<value<<endl; //输出八进制整型变量
2.代码片段2
代码片段二中主要演示了采用precision()与setprecision()方法成员控制浮点数的精度。这两个方法主要用于控制浮点小数的点右部的位数。在输出流中一旦设置精度,随后的输出流中都应用了该精度。当需要改变浮点精度时,则需要再次显式的调用该方法。
//代码片段二
doublevalue = sqrt(3.0); //定义double型变量value,3开平方初始化变量value
cout<<setiosflags(ios::fixed)<<endl; //表明浮点数以固定小数点位置格式输出
for(inti = 0;i <= 5;i++) //for循环控制流程
{
cout.precision(i); //cout输出对象调用precision方法,输出value变量小数点后 //i位,第i+1位四舍五入
cout<<value<<endl; //打印输出value具体值
}
for(inti = 0;i <= 5;i++) //for循环控制流程
{
cout<<setprecision(i)<<value<<endl; //通过setprecision控制小数点后显示位数
}
代码中首先定义double型数据变量value,调用库函数sqrt()计算传入的实参的平方根,并将计算结果初始化给value。随后,通过setiosflags()方法设置表明浮点小数以固定的小数位数显示。之后两个for循环中,则使用cout对象直接调用方法precision()以及直接在输出流中插入setprecision()方法,设定浮点数的位数,最后打印开平方计算结果。
3.代码片段3
代码片段三种主要演示setw()与width()方法设置输出流中的宽度。该方法调用设置好输出流宽度后,随后的输出流数据将以该宽度来显示。如果显示的数据比设定的宽度大,则会被截断显示。如果显示的数据比设定的宽度小,则会采用填充字符来填满未足的位数。通常C++中默认情况下为采用空字符填充。
//代码片段三
stringmystring; //定义字符串对象mystring
cout<<"Pleaseinput string value:"<<endl; //提示输入字符串
cin.width(4); //输入流对象cin调用width方法,设定输出显示宽度
cin>>mystring; //输入字符串
cout<<mystring<<endl; //输出字符串对象mystring
cout<<setw(8)<<mystring<<endl; //设置输出字符串对象值的显示宽度
上述代码中首先定义一个空字符串对象mystring,随后提示从键盘设备输入字符串。随后采用cin对象调用其width()方法设定当前输出流中的宽度。从输入设备键入对应的字符串最终存放于mystring中。之后以设定的宽度输出打印mystring字符串。最后,重新使用setw()方法调整输出流的宽度并打印其字符串对象结果。
4.代码片段4
代码片段四则是演示了采用setf与setiosflags两种方法操作设置输出流中数据对齐的应用。代码中首先定义字符串变量value,并且初始化为字符串“string”。随后在输出流中插入设置输出数据宽度方法,将输出宽度设定为10,并输出打印字符串变量value。
默认情况下,cout输出的数据为右对齐方式,即此时输出value的值为右对齐供10个字节右对齐,左边空出来的部分默认采用空白符填补。随后分别采用cout对象调用setf()方法根据参数ios::left设定输出数据为左对齐方式。空出部分默认在右边填充空字符。而方法unsetf方法的调用则卸载加在输出流上的左对齐设定,之后采用setiosflags方法调用设定实现同样的对齐功能。
//代码片段四
stringvalue = "string";
cout<<"myvalue:"<<setw(10)<<value<<setw(10)<<endl;
cout.setf(ios::left,ios::adjustfield);
cout<<value<<endl;
cout.unsetf(ios::left);
cout<<setw(10)<<value<<endl;
cout<<setw(10)<<setiosflags(ios::left)<<value<<endl;
cout<<setw(10)<<resetiosflags(ios::left)<<value<<endl;
5.代码片段5
代码片段五则首先根据setw()方法在输出流中设定数据输出宽度为10字节。随后采用cout对象调用setf()方法设定输出数据对齐方式,上述设定为左对齐方式。之后采用cout对象提供的fill()方法在设定宽度下输出字符串空出部分的填充符为'$',之后打印输出字符串变量value。最后则采用了另外一种实现方式实现同上的功能,主要演示了setfill()方法的使用,将输出左对齐的字符串空出部分填补为'*'。
//代码片段五
stringvalue = "string";
cout<<"myvalue:"<<setw(10)<<value<<endl;
cout.setf(ios::left,ios::adjustfield);
cout.fill('$');
cout<<setw(10)<<value<<endl;
cout.unsetf(ios::left);
cout<<setw(10)<<value<<endl;
cout<<setw(10)<<setfill('*')<<setiosflags(ios::left)<<value<<endl;
cout<<setw(10)<<resetiosflags(ios::left)<<value<<endl;
C++中针对输入输出处理提供了大量的操纵算子。通过这些操纵算子,能够实现流中各种格式化输出。本小节上述代码片段初学者可以通过编辑简单的应用程序将这些片段加入其中,进行测试学习。同时,用户也可以使用C++标准I/O提供的更多的操纵算子进行练习。