稚久|为什么不是简单封装而是重新定义,C++|输入输出类库的由来( 二 )


稚久|为什么不是简单封装而是重新定义,C++|输入输出类库的由来
文章图片
类ios_base声明了所有流类共有的内容 , 不依赖于流所处理的字符类型 。 这些声明大部分是常量以及处理这些常量的函数 。 其他类是以基础字符类型为参数的模板 。 例如类istream , 定义如下:
typedefbasic_istreamistream;C++中也用wchar_t来替换char定义了所有的输入输出流类 。 模板basic_ios定义了输入和输出通用的函数 , 但是这依赖于基础字符类型(几乎不使用它们) 。 模板basic_istream定义了一般的输入函数 , basic_ostream定义了一般的输出函数 。 后面介绍的文件流类和字符串流类增加了特殊的流处理功能 。
在输入输出流类库中 , 重载了两种运算符以简化输入输出流的使用 。 运算符<>常用作提取符(extractor) 。 提取符按照目标对象的类型解析输入信息 。 举例说明 , 可以使用cin对象 , 它是输入流 , 相当地C中的stdin(键盘输入) , 即可重定向标准输入(redirectablestandardinput) 。 在代码中包含头文件时 , 就会预定义这个对象 。
所有的内置数据类型都重载了operator<
(相当于标准输出(standardoutput) , 如输出到显示屏 , 同样地 , cerr对象相当于标准错误输出(standarderror)) 。
重载的插入符和提取符可以连续使用 , 构成复杂的表达式 , 使得写(和读)更容易 。
为自己的类定义插入符和提取符 , 就是重载相关的运算符以完成正确的操作 , 即:
1)第1个参数定义成流(输入为istream,输出为ostream)的非const引用 。
2)执行向/从流中插入/提取数据的操作(通过处理对象的组成元素) 。
3)返回流的引用 。
输入输出流应该是非常量 , 因为处理流数据将改变流的状态 。 通过返回流 , 如前所述 , 可
【稚久|为什么不是简单封装而是重新定义,C++|输入输出类库的由来】以将这些流操作链接成单一的语句 。
举个例子 , 考虑如何输出一个MM-DD-YYYY格式的Date类对象 。 下面的代码重载了插入符:
ostream&operator<<(ostream&os,constDate&d){charfillc=os.fill('0');os<这个函数不能设为Date类的成员函数 , 因为运算符<
ostream的成员函数fill()用于更换填充字符(paddingcharacter),当输出域(field)的宽度大于输出数据长度时 , 使用填充字符填充超出部分 , 域宽由操纵算子(manipulator)setw()决定 。 使用"0"作为前导填充字符 , 所以显示10月之前的月份时 , 如显示9月份为"09" 。 函数fill()返回原有的填充字符(默认为一个空格符) , 以便在后面使用操纵算子setfill()恢复这个填充字符 。
使用输入输出流类操纵文件比使用C语言中的stdio更容易、更安全 。 打开一个文件要做的全部工作就是创建一个对象(这是构造函数所做的工作) 。 不需要显式地关闭文件(尽管能使用成员函数close()来关闭文件) , 因为当对象超出作用域时析构函数会关闭文件 。 构造一个ifstream对象用于创建默认的输入文件 。 构造一个ofstream对象用于创建默认的输出文件 。 一个fstream对象既可以用于输入文件 , 也可以用地输出文件 。
下图说明了适用于输入输出流类的文件流类:
稚久|为什么不是简单封装而是重新定义,C++|输入输出类库的由来
文章图片
和以前一样 , 这里实际使用的类都是由类型定义的模板的特化 。 例如 , ifstream用来处
理char文件 , 定义如下:
typedefbasic_ifstreamifstream;


推荐阅读