istream类方法 满载的抽取操作符和 cin输入

istream类方法 重载的抽取操作符和 cin输入

istream类方法 重载的抽取操作符和 cin输入
2010年09月04日
  重载的抽取操作符 >>
  istream类(在头文件iostream中定义)重载了抽取操作符 >> ,使之能够识别下面的这些基本类型:
  signed char &                unsigned char &
  char &                           short &
  unsigned short &          int &
  unsigned int &              long &
  unsigned long &           float &
  double &                      long double &
  这些操作符函数被称为格式化输入函数(formatted input functions) ,因为它们可以将输入数据转换为目标指定的格式。
  典型的操作符函数的原型如下:
  istream & operator>> (int &);
  参数和返回值都是引用。因此cin能够直接修改用作参数的变量的值。
  可以将hex、oct和dec控制符与cin一起使用,来指定将整数输入解释为十六进制、八进制还是十进制格式。例如:
  cin >> hex;
  将输入12或0x12解释为十六进制的12或十进制的18,而将ff或FF解释为十进制的255。
  该类还为下列字符指针类型重载了>> 抽取操作符:
  signed char *        char *       unsigned char *
  对于这种类型的参数,抽取操作符将读取输入中的下一个单词,将它放置到指定的地址,并加上一个空值字符,使之成为一个字符串。
  每个抽取操作符都返回调用对象的引用,这使得能够将输入拼接起来,就像拼接输出那样:
  char name[20];
  float fee;
  int group;
  cin >> name >> fee >> group;
  cin>> 如何检查输入
  cin>> 跳过空白(空格、换行符和制表符),直到遇到非空白字符。
  在单字符模式下,>>操作符将读取该字符,将它放置到指定的位置。
  在其他模式下,>>操作符将读取一个指定类型的数据。它的读取从非空白字符开始,到与目标类型不匹配的第一个字符之间的全部内容。
  当输入未满足程序的期待时,抽取操作符将不会修改参数的值,并返回0(false)。
  流状态
  cin或cout对象包含一个描述流状态(stream state) 的数据成员(从ios_base类那里继承的)。
  流状态被定义为iostate 类型,而iostate是一种bitmask 类型。由3个ios_base元素组成: eofbit 、badbit 和failbit ,其中每个元素都是一位,可以是1(设置)或0(清除)。
  当cin操作到达文件末尾时,它将设置eofbit;
  当cin操作未能读取到预期的字符时,它将设置failbit。
  I/O失败(如试图读取不可访问的文件或试图写入受保护的磁盘),也可能将failbit设置为1。
  在一些无法诊断的失败破坏流时,badbit元素将被设置。
  当全部3个状态位都设置为0时,说明一切顺利。
  下图列出了这些位和一些报告或改变流状态的ios_base方法。
  
  1. 设置状态
  clear() 方法将状态设置为它的参数。例如:
  clear();
  将使用默认参数0,清除全部3个状态位。
  clear(eofbit);
  将状态设置为eofbit;也就是说,eofbit将被设置,另外两个状态位被清除。
  setstate() 方法只影响其参数中已设置的位。例如:
  setstate(eofbit);
  将设置eofbit,而不会影响其他位。
  2. I/O和异常
  exceptions() 方法用来控制异常如何被处理。
  exceptions()方法返回一个位字段,它包含3位,分别对应于eofbit、failbit和badbit。
  修改流状态后,clear()方法将当前的流状态与exceptions()返回值进行比较。如果在返回值中某一位被设置,而当前状态中的对应位也被设置,则clear()将引发ios_base::failbit异常。如果两个值都设置了badbit,将发生这种情况。
  如果exceptions()返回goodbit ,则不会引发任何异常。
  os_base::failbit异常类是从std::exception类派生而来的,因此包含一个what()方法。
  exceptions()的默认设置为goodbit,不会引发异常。
  重载的exceptions(iostate)函数使得能够控制其行为:
  cin.exceptions(badbit);      // setting badbit causes exception to be thrown
  位操作符OR (| )使得能够指定多位。例如:
  cin.exceptions(badbit | eofbit);
  如果badbit或eofbit随后被设置,将引发异常。
  3. 流状态的影响
  只有在流状态良好(所有的位都被清除)的情况下,才能正确的返回true或false。
  设置流状态位有一个非常重要的后果: 流将对后面的输入或输出关闭,直到位被清除。
  例如下面的代码不能工作:
  while(cin >> input)
  sum += input;
  cout > input;         // won't work
  然而,仅仅使用clear()方法还不足以重新设置流状态。因为导致输入循环终止的不匹配输入仍留在输入队列中,程序必须跳过它。
  一种方法是一直读取字符,直到到达空白为止:
  while( !isspace(cin.get() ))
  continue;    // get rid of bad input
  isspace()函数是一个cctype函数,它在参数是空白字符时返回true。
  另一种方法是,丢弃行中的剩余部分,而不仅仅是下一个单词:
  while(cin.get() != '\n')
  continue;    // get rid of line
  假设循环是由于到达文件尾或者由于硬件故障而终止的,则上面的错误处理代码将毫无意义。
  可以使用fail() 、eof() 或bad() 方法来判断假设是否成立。
  其他istream类方法
  get(char&) 和get(void) 方法提供不跳过空白的单字符输入功能。
  get(char*, int, char) 和getline(char*, int, char) 函数在默认情况下读取整行而不是一个单词。
  它们被称为非格式化输入函数(unformatted input functions) 。
  1. 单字符输入
  使用char参数或没有参数的情况下,get()方法读取下一个输入字符,即使该字符是空格、制表符或换行符。
  get(char&) 版本将输入字符赋给其参数。
  get(void) 版本将输入字符转换为整型(通常是int),并将其返回。
  由于get(char&)版本的读取方式,便可以使用下面的判断语句:
  char ch;
  cin.get(ch);
  while(ch != '\n')
  ...
  假如改为cin >> ch 循环将不会停止。
  get(char&)成员函数返回一个指向用于调用它的istream对象的引用,这意味着可以拼接输入:
  char c1,c2,c3;
  cin.get(c1).get(c2) >> c3;
  如果cin.get(char&)到达文件尾--无论是真正的,还是通过键盘仿真的文件尾(DOS为按下+;UNIX为在行首按下+ ),它都不会给其参数赋值。该方法还调用setstate(failbit),导致cin的测试结果为false。
  get(void)成员函数也读取空白,但使用返回值来将输入传递给程序。例如:
  char ch;
  ch = cin.get();         // use return value
  因此,试图拼接该方法来输入,将是错误的。
  如果到达文件尾后(真正的或者仿真的文件尾都一样),该方法将返回值EOF --iostream头文件的一个符号常量。
  int ch;
  while( (ch = cin.get() ) != EOF)
  ...
  这里应将ch的类型声明为int,而不是char。因为值EOF可能无法使用char类型来表示。
  下图总结了这两个版本的特性。
  
  2. 字符串输入
  istream & get(char *, int, char);
  istream & get(char *, int);
  istream & getline(char *, int, char);
  istream & getline(char *, int);
  上述中的第一个参数是用于放置输入字符串的内存单元的地址。
  第二个参数比要读取的最大字符数大1,额外的一个字符用于存储结尾的空字符,以便将输入存储为一个字符串。
  第三个参数指定用作分界符的字符,只有两个参数的版本将换行符用作分界符。
  上述函数都在读取最大数目的字符或遇到分界符后为止。
  get()和getline()之间的主要区别在于,前者将分界符(默认为换行符)留在输入流中,这样接下来的输入操作首先看到的将是分界符,而getline()抽取并丢弃输入流中的分界符。
  ignore() 成员函数接受两个参数。原型如下:
  istream & ignore(int =1, int = EOF);
  第一个参数是数字,指定要读取的最大字符数。
  第二个参数是字符,用作输入分界符。例如:
  cin.ignore(255,'\n')
  上述语句将读取并丢弃接下来的255个字符或直到到达第一个换行符。
  该函数返回调用对象,这使得能够拼接函数调用,例如:
  cin.ignore(255,'\n').ignore(255,'\n');
  3. 意外字符串输入
  get(char *, int)和getline()如果不能抽取字符,它们将把空值字符放置到输入字符串中,并使用setstate()设置failbit。
  如果遇到文件尾,将设置eofbit,如果遇到流被破坏(如设备故障),将设置badbit。
  对于get(char *, int)来说,如果输入了一个空行,将导致不能抽取字符,例如:
  char temp[80];
  while(cin.get(temp, 80)   // terminates on empty line
  ...
  但空行并不会导致getline()设置failbit。因为getline()仍将抽取换行符,虽然不会存储它。
  如果希望getline()在遇到空行时终止循环,则可以这样编写:
  char temp[80];
  while(cin.getline(temp,80) && temp[0] != '\0');    // terminates on empty line
  假设队列中的字符数等于或超过了输入方法指定的最大字符数。例如:
  char tmep[30];
  while(cin.getline(temp,30) );
  如果读取了29个字符,并且输入流中的下一个字符不是分界符,则设置failbit。
  对于get(char *, int)方法,它首先测试字符数,然后检测是否为文件尾以及下一个字符是否是分界符。如果它读取了最大数目的字符,则不设置failbit标记。
  可以用peek() 来查看下一个输入字符,如果它是换行符,则说明get()已读取了整行;否则说明是在到达行尾前停止的。
  这种技术对于getline()不适用,因为该方法读取并丢弃换行符,因此查看下一个字符无法知道任何情况。
  其他istream方法
  read() 函数读取指定数目的字节,并将它们存储在指定的位置中。例如:
  char gross[144];
  cin.read(gross,144);
  该方法不会在输入后加上空值字符,因此不能将输入转换为字符串。
  它常与ostream write() 函数结合使用,来完成文件输入和输出。
  该方法的返回类型为istream & 。
  peek() 函数返回输入中的下一个字符,但不抽取输入流中的字符。
  gcount() 方法返回最后一个非格式化抽取方法读取的字符数。
  这意味着字符是由get()、getline()、ignore()、read()方法读取的,而不是由抽取操作符(>>)读取的。
  putback() 函数将一个字符插入到输入字符串中,被插入的字符将是下一条输入语句读取的第一个字符。
  该方法接受一个char参数--要插入的字符。
  返回类型为istream & 。