面向对象的标准库
C++ 的输入/输出(input/output)由标准库提供。
标准库定义了一些类型,支持对文件和控制窗口等设备的读写(IO)。
另外一些类型,使 string 对象能够像文件一样操作,而无须 IO 就能实现数据与字符之间的转换。
这些 IO 类型都定义了如何读写内置数据类型的值。
此外,通常类的设计者还可以使用 IO 标准库设施读写自定义类的对象。
类类型通常使用 IO 标准库为内置类型定义的操作符和规则来进行读写。
getline 函数:
需要分别取 istream 类型和 string 类型的两个引用形参,
其功能是从 istream 对象读取一个单词,然后写入 string 对象中。
为了同时支持或使用不同类型设备以及不同大小的字符流,
标准库使用了继承(inheritance)来定义一组面向对象(object-oriented)类。
不过,一般而言,通过继承关联起来的类型都共享共同的接口。
当一个类继承另一个类时,这两个类通常可以使用相同的操作。
如果两种类型存在继承关系,则可以说一个类“继承”了其父类的行为 —— 接口。
C++ 中所提及的父类称为基类(base class),而继承而来的类则称为派生类(derived class)。
IO 类型在三个独立的头文件中定义:
iostream 定义读写控制窗口的类型,
fstream 定义读写已命名文件的类型,
sstream 所定义的类型则用于读写存储在内存中的 string 对象。
在 fstream 和 sstream 里定义的每种类型都是从 iostream 头文件中定义的相关类型派生而来。
下面列出了 C++ 的 IO 类 ——
/** IO 标准库类型和头文件 **/ Header Type iostream istream 从流中读取 ostream 写到流中去 iostream 对流进行读写;从 istream 和 ostream 派生而来 fstream ifstream 从文件中读取;由 istream 派生而来 ofstream 写到文件中去;由 ostream 派生而来 fstream 读写文件;由 iostream 派生而来 sstream istringstream 从 string 对象中读取;由 istream 派生而来 ostringstream 写到 string 对象中去;由 ostream 派生而来 stringstream 对 string 对象进行读写;由 iostream 派生而来
下图阐明这些类型之间的继承关系 ——
继承关系通常可以用类似于家庭树的图解说明。
最顶端的圆圈代表基类(或称“父类”),基类和派生类(或称“子类”)之间用线段连接。
istream 是 ifstream 和 istringstream 的基类,同时也是 iostream 的基类,
而 iostream 则是 stringstream 和 fstream 的基类。
由于 ifstream 和 istringstream 类型继承了 istream 类,因此已知这两种类型的大量用法。
读 istream 对象的程序也可用于读文件(使用 ifstream 类型)或者 string 对象(使用 istringstream 类型)。
类似地,提供输出功能的程序同样可用 ofstream 或 ostringstream 取代 ostream 类型实现。
除了 istream 和 ostream 类型之外,iostream 头文件还定义了 iostream 类型。
iostream 类型由 istream 和 ostream 两者派生而来。
这意味着 iostream 对象共享了它的两个父类的接口。
也就是说,可使用 iostream 类型在同一个流上实现输入和输出操作。
对 IO 类型使用继承还有另外一个重要的含义:
如果函数有基类类型的引用形参时,可以给函数传递其派生类型的对象(反过来则是错误的)。
这就意味着:
对 istream& 进行操作的函数,也可使用 ifstream 或者 istringstream 对象来调用。
类似地,形参为 ostream& 类型的函数也可用 ofstream 或者 ostringstream 对象调用。
因为 IO 类型通过继承关联,所以可以只编写一个函数,而将它应用到3种类型的流上:
1) 控制台 2) 磁盘文件 3)字符串流。
国际字符的支持
迄今为止,所描述的流类(stream class)读写的是由 char 类型组成的流。
此外,标准库还定义了一组相关的类型,支持 wchar_t 类型。
每个类都加上“w”前缀,以此与 char 类型的版本区分开来。
于是,wostream、wistream 和 wiostream 类型从控制窗口读写 wchar_t 数据。
相应的文件输入输出类是 wifstream、wofstream 和 wfstream。
而 wchar_t 版本的 string 输入/输出流则是 wistringstream、wostringstream 和 wstringstream。
标准库还定义了从标准输入输出读写宽字符的对象。
这些对象加上“w”前缀,以此与 char 类型版本区分:
1) wchar_t 类型的标准输入对象是 wcin;
2) 标准输出是 wcout;
3) 而标准错误则是 wcerr。
每一个 IO 头文件都定义了 char 和 wchar_t 类型的类和标准输入/输出对象:
基于流的 wchar_t 类型的类和对象在 iostream 中定义,
宽字符文件流类型在 fstream 中定义,
IO 对象不可复制或赋值
出于某些原因(其原因将在后面学习类和继承时阐明),标准库类型不允许做复制或赋值操作。
ofstream out1, out2; out1 = out2; // error: cannot assign stream objects // print function: parameter is copied ofstream print(ofstream); out2 = print(out2); // error: cannot copy stream objects
这个要求有两层特别重要的含义:
第一层含义:只有支持复制的元素类型可以存储在 vector 或其他容器类型里。
由于流对象不能复制,因此不能存储在 vector(或其他)容器中,
(即,不存在存储流对象的 vector 或其他容器)。
第二个含义:形参或返回类型也不能为流类型。
如果需要传递或返回 IO 对象,则必须传递或返回指向该对象的指针或引用:
ofstream &print(ofstream&); // ok: takes a reference, no copy while (print(out2)) { /* ... */ } // ok: pass reference to out2
一般情况下,如果要传递 IO 对象以便对它进行读写,可用非 const 引用的方式传递这个流对象。
对 IO 对象的读写会改变它的状态,因此引用必须是非 const 的。