JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris Studio 12.3:C++ 用户指南     Oracle Solaris Studio 12.3 Information Library (简体中文)
search filter icon
search icon

文档信息

前言

第 1 部分C++ 编译器

1.  C++ 编译器

2.  使用 C++ 编译器

3.  使用 C++ 编译器选项

第 2 部分编写 C++ 程序

4.  语言扩展

5.  程序组织

6.  创建和使用模板

7.  编译模板

8.  异常处理

9.  改善程序性能

10.  生成多线程程序

第 3 部分库

11.  使用库

12.  使用 C++ 标准库

13.  使用传统 iostream

13.1 预定义的 iostream

13.2 iostream 交互的基本结构

13.3 使用传统 iostream

13.3.1 使用 iostream 进行输出

13.3.1.1 定义自己的插入运算符

13.3.1.2 处理输出错误

13.3.1.3 刷新

13.3.1.4 二进制输出

13.3.2 使用 iostream 进行输入

13.3.3 定义自己的提取运算符

13.3.4 使用 char* 提取器

13.3.5 读取任何单一字符

13.3.6 二进制输入

13.3.7 查看输入

13.3.8 提取空白

13.3.9 处理输入错误

13.3.10 结合使用 iostreamstdio

13.4 创建 iostream

13.4.1 使用类 fstream 处理文件

13.4.1.1 打开模式

13.4.1.2 在未指定文件的情况下声明 fstream

13.4.1.3 打开和关闭文件

13.4.1.4 使用文件描述符打开文件

13.4.1.5 在文件内重新定位

13.5 iostream 赋值

13.6 格式控制

13.7 操纵符

13.7.1 使用无格式操纵符

13.7.2 参数化操纵符

13.8 strstream:用于数组的 iostream

13.9 stdiobuf:用于 stdio 文件的 iostream

13.10 处理 streambuf

13.10.1 streambuf 指针类型

13.10.2 使用 streambuf 对象

13.11 iostream 手册页

13.12 iostream 术语

14.  生成库

第 4 部分附录

A.  C++ 编译器选项

B.  Pragma

词汇表

索引

13.3 使用传统 iostream

要使用来自传统 iostream 库的例程,必须针对所需的库部分将头文件包括进来。下表对头文件进行了具体描述。

表 13-1 iostream 例程头文件

头文件
说明
iostream.h
声明 iostream 库的基本功能。
fstream.h
声明文件专用的 iostreamstreambuf。包括了 iostream.h
strstream.h
声明字符数组专用的 iostreamstreambuf。包括了 iostream.h
iomanip.h
声明操纵符:iostream 中插入或提取的值有不同的作用。包括了 iostream.h
stdiostream.h
(已过时)声明 stdio 文件专用的 iostreamstreambuf。包括了 iostream.h
stream.h
(已过时)包括了 iostream.hfstream.hiomanip.hstdiostream.h。用于兼容 C++ 1.2 版的旧式流。

通常程序中不需要所有这些头文件,而仅包括所需声明的头文件。缺省情况下,libiostream 包含传统的 iostream 库。

13.3.1 使用 iostream 进行输出

使用 iostream 进行的输出通常依赖于重载的左移运算符 (<<)(在 iostream 上下文中,称为插入运算符)。要将值输出到标准输出,应将值插入预定义的输出流 cout 中。例如,要将给定值 someValue 发送到标准输出,可以使用以下语句:

cout << someValue;

对于所有内置类型,都会重载插入运算符,且 someValue 表示的值转换为其适当的输出表示形式。例如,如果 someValuefloat<< 运算符会将该值转换为带小数点的适当数字序列。此处是将 float 值插入输出流中,因此 << 称为浮点插入器。通常,如果给定类型 X<< 称为 X 插入器。ios(3CC4) 手册页中讨论了输出格式以及如何控制输出格式。

iostream 库不支持用户定义类型。如果您定义要以您自己的方式输出的类型,则必须定义插入器(即,重载 << 运算符)来正确处理它们。

<< 可以多次应用。要将两个值插入 cout 中,可以使用类似于以下示例中的语句:

cout << someValue << anotherValue;

以上示例的输出在两个值间不显示空格。因此您可能会要按以下方式编写编码:

cout << someValue << " " << anotherValue;

运算符 << 优先作为左移运算符(其内置含义)使用。与其他运算符一样,总是可以使用圆括号来指定操作顺序。必要时可使用括号来避免出现优先级问题。下列四个语句中,前两个是等价的,但后两个不是。

cout << a+b;              // + has higher precedence than <<
cout << (a+b);
cout << (a&y);            // << has precedence higher than &
cout << a&y;            // probably an error: (cout << a) & y

13.3.1.1 定义自己的插入运算符

以下示例定义了 string 类:

#include <stdlib.h>
#include <iostream.h>


class string {
private:
    char* data;
    size_t size;

public:
    // (functions not relevant here)

    friend ostream& operator<<(ostream&, const string&);
    friend istream& operator>>(istream&, string&);
};

在此示例中,必须将插入运算符和提取运算符定义为友元,因为 string 类的数据部分是 private

ostream& operator<< (ostream& ostr, const string& output)
{    return ostr << output.data;}

以下示例显示了为用于 string 而重载的 operator<< 的定义。

cout << string1 << string2;

运算符 <<ostream&(也就是对 ostream 的引用)作为其第一个参数,并返回相同的 ostream,这样就可以在一个语句中合并多个插入。

13.3.1.2 处理输出错误

通常情况下,重载 operator<< 时不必检查错误,因为有 iostream 库传播错误。

出现错误时,所在的 iostream 会进入错误状态。iostream 状态中的各个位根据错误的一般类别进行设置。iostream 中定义的插入器不会尝试将数据插入处于错误状态的任何流,因此这种尝试不会更改 iostream 的状态。

通常,处理错误的推荐方法是定期检查某些中心位置中输出流的状态。如果存在错误,则应该以某种方式进行处理。本章假定您定义了函数 error,该函数接受字符串并中止程序。error 不是一个预定义函数。有关 error 函数的示例,请参见13.3.9 处理输入错误。您可以使用 运算符 ! 来检查 iostream 的状态,如果 iostream 处于错误状态,则会返回非零值。例如:

if (!cout) error("output error");

还有另外一种方法来测试错误。ios 类定义了 operator void *(),因此当发生错误时,它将返回 NULL 指针。您可以使用如下例所示的语句:

if (cout << x) return; // return if successful

也可以使用函数 good,它是 ios 的成员:

if (cout.good()) return; // return if successful

错误位在 enum 中声明:

enum io_state {goodbit=0, eofbit=1, failbit=2,
badbit=4, hardfail=0x80};

有关错误函数的详细信息,请参见 iostream 手册页。

13.3.1.3 刷新

与大多数 I/O 库一样,iostream 通常会累积输出并将其发送到较大且效率通常较高的块中。如果要刷新缓冲区,请插入特殊值 flush。例如:

cout << "This needs to get out immediately." << flush;
 

flush 是一种称为操纵符的对象示例,它是一个值,可以插入 iostream 中以起到一定作用,而不是使输出其值。这些值实际上是函数,它们接受 ostream&istream& 参数,在对其执行某些操作后返回其参数(请参见13.7 操纵符)。

13.3.1.4 二进制输出

要获得原始二进制形式的值输出,请使用以下示例所示的成员函数 write。该示例显示了原始二进制形式的 x 输出。

cout.write((char*)&x, sizeof(x));

以上示例将 &x 转换为 char*,这违反了类型规程。一般情况下,这样做无关大碍,但如果 x 的类型是具有指针、虚拟成员函数的类或是需要 nontrivial 构造函数操作的类,就无法正确读回以上示例写入的值。

13.3.2 使用 iostream 进行输入

使用 iostream 进行的输入类似于输出。需要使用提取运算符 >>,可以像插入操作那样将提取操作串接在一起。例如:

cin >> a >> b;

该语句从标准输入获得两个值。与其他重载的运算符一样,所使用的提取器取决于 ab 的类型。如果 ab 具有不同的类型,则会使用两个不同的提取器。ios(3CC4) 手册页中详细讨论了输入格式以及如何控制输入格式。通常,前导空白字符(空格、换行符、标签、换页等)被忽略。

13.3.3 定义自己的提取运算符

要输入新的类型时,如同重载输出的插入运算符,请重载输入的提取运算符。

string 定义了其提取运算符,如以下代码示例所示:

示例 13-1 string 提取运算符

istream& operator>> (istream& istr, string& input)
{
    const int maxline = 256;
    char holder[maxline];
    istr.get(holder, maxline, ”\n’);
    input = holder;
    return istr;
}

get 函数从输入流 istr 读取字符,并将其存储在 holder 中,直到读取了 maxline-1 字符、遇到新行或 EOF(无论先发生哪一项)。然后,holder 中的数据以空终止。最后,holder 中的字符复制到目标字符串。

按照约定,提取器转换其第一个参数中的字符(此示例中是 istream& istr),将其存储在第二个参数(始终是引用),然后返回第一个参数。因为提取器会将输入值存储在第二个参数中,所以第二个参数必须是引用。

13.3.4 使用 char* 提取器

使用该预定义提取器时,请务必小心,它可能会导致问题。请按如下方式使用该提取器:

char x[50];
cin >> x;

该提取器跳过前导空白,提取字符并将其复制到 x 中,直至遇到另一个空白字符。然后,它使用终止空 (0) 字符完成字符串。请谨慎使用该提取器,因为输入可能会溢出给定的数组。

您还必须确保指针指向了分配的存储。以下示例显示了一个常见错误:

char * p; // not initialized
cin >> p;

由于将存储输入数据的位置不确定,因此您的程序可能会中止。

13.3.5 读取任何单一字符

除了使用 char 提取器外,还可以使用任一形式的 get 成员函数获取一个字符。例如:

char c;
cin.get(c); // leaves c unchanged if input fails

int b;
b = cin.get(); // sets b to EOF if input fails

注 - 与其他提取器不同,char 提取器不会跳过前导空白


以下示例显示了一种方法,该方法只跳过空格并在制表符、换行符或任何其他字符处停止:

int a;
do {
    a = cin.get();
   }
while(a ==’ ’);

13.3.6 二进制输入

如果需要读取二进制值(如使用成员函数 write 写入的值),可以使用 read 成员函数。以下示例说明了如何使用 read 成员函数输入原始二进制形式的 x,这是先前使用 write 的示例的反向操作。

cin.read((char*)&x, sizeof(x));

13.3.7 查看输入

可以使用 peek 成员函数查看流中的下一个字符,而不必提取该字符。例如:

if (cin.peek()!= c) return 0;

13.3.8 提取空白

缺省情况下,iostream 提取器跳过前导空白。以下示例先关闭了 cin 跳过空白功能,然后将其打开:

cin.unsetf(ios::skipws); // turn off whitespace skipping
...
cin.setf(ios::skipws); // turn it on again

可以使用 iostream 操纵符 wsiostream 中删除前导空白,不论是否启用了跳过功能。以下示例说明了如何从 iostream istr 中删除前导空白:

istr >> ws;

13.3.9 处理输入错误

按照约定,第一个参数为非零错误状态的提取器不能从输入流提取任何数据,且不能清除任何错误位。失败的提取器至少应该设置一个错误位。

对于输出错误,您应该定期检查错误状态,并在发现非零状态时采取某些操作(诸如终止)。! 运算符测试 iostream 的状态。例如,如果输入字母字符用于输入,以下代码就会产生输入错误:

#include <stdlib.h>
#include <iostream.h>
void error (const char* message) {
     cerr << message << "\n";
     exit(1);
}
int main() {
     cout << "Enter some characters: ";
     int bad;
     cin >> bad;
     if (!cin) error("aborted due to input error");
     cout << "If you see this, not an error." << "\n";
     return 0;
}

ios 具有可用于错误处理的成员函数。详细信息请参见手册页。

13.3.10 结合使用 iostreamstdio

可以将 stdio 用于 C++ 程序,但在程序内的同一标准流中混合使用 iostreamstdio 时,可能会发生问题。例如,如果同时向 stdoutcout 写入,会发生独立缓冲,并产生不可预料的结果。如果从 stdincin 两者进行输入,问题会更加严重,因为独立缓冲可能会导致输入不可用。

要消除标准输入、标准输出和标准错误中的这种问题,就请在执行输入或输出前使用以下指令。它将所有预定义的 iostream 与相应的预定义 stdio 文件连接起来。

ios::sync_with_stdio();

因为在预定义流作为连接的一部分成为无缓冲流时,性能会显著下降,所以该类型的连接不是缺省连接。您可以在同一程序中使用应用于不同文件的 stdioiostream,也就是说,您可以使用 stdio 例程写入到 stdout,同时还可以写入到连接到 iostream 的其他文件。可以打开 stdio 文件进行输入,也可以从 cin 读取,只要不同时尝试从 stdin 读取即可。