C++中cin对象输入失败时为何可判定为false且能调用成员函数
C++ cin流对象布尔判定问题解答
以下代码片段摘自C++ Iostreams Handbook by Steve Teale,其思路是通过死循环调用cin,持续提示用户输入正确内容,仅当输入合法时才退出循环。
该代码运行正常,但我对if(cin){...}语句存在疑惑,原本认为此处应该写为if(!cin.fail()){...}。
#include <limits.h> #include <iostream> using namespace std; int main() { int n; cin.unsetf(ios::skipws); // 关闭空白字符跳过功能 cout << "Enter a value for n, followed by [Enter]: " << flush; for(;;) { cin >> n; if(cin) { // cin处于良好状态,输入合法 cin.ignore(INT_MAX, '\n'); // 清除多余的换行符 break; } // 提问者注释(非原作者内容) // 此代码段中cin判定结果为false // cin.clear(); // 清除错误状态 cin.ignore(INT_MAX, '\n'); // 清除非法输入的垃圾字符 cout << "That was no good, try again: " << flush; } return 0; }
问题
cin是流对象,不是可被设置为null的指针,为什么输入失败时cin会被判定为false(即等效于0或空值)?而且在cin判定为false的代码段中,我们仍然可以调用clear、ignore这类成员函数,这是如何实现的?
解答
这两个问题本质都和C++标准库对流类的设计逻辑有关:
- 首先解释
if(cin)能直接判定真假的原因:C的所有标准流类(包括std::istream、std::ostream等)都自定义了显式布尔类型转换函数explicit operator bool() const。当你把流对象放在if、while这类需要布尔值的语境里时,编译器会自动调用这个转换函数,返回流的状态是否正常:只要流的failbit(输入输出操作失败,比如类型不匹配)和badbit(流发生不可逆损坏)都没有被置位,就返回true,否则返回false。这个设计本身就是为了简化流状态判断的代码,if(cin)和你认为的if(!cin.fail())效果完全一致,属于标准提供的语法糖。
补充说明:在C11标准之前,流类实现的是转换到void*的运算符,判定逻辑和现在的布尔转换完全一致,这也是为什么有些旧代码里会出现if(cin != NULL)这种写法的原因,本质都是判断状态位,和对象本身是否为指针、是否为空没有任何关系。 - 第二个问题,判定为false还能调用成员函数的原因:
operator bool()返回false仅仅代表流的内部状态标志位被设置为错误状态,完全不影响cin对象本身的有效性。cin是程序启动时就初始化的全局istream类实例,整个程序运行周期内都合法存在,当然可以正常调用它的成员函数。clear()方法的作用就是重置流的内部状态标志位为正常状态,之后流就可以继续执行读写操作了。
内容的提问来源于stack exchange,提问作者Sandeep
相关产品推荐
相关产品推荐

