流对象为什么可以作为条件表达式?
文章目录
转载:
http://blog.csdn.net/bladelyer/article/details/8505912.
http://blog.csdn.net/andyelvis/article/details/4529592
原理解释
相信很多人都遇到过这样的例子:
|
|
似乎,大多数初学者都不明白【cin » str】怎么可以作为while的判断语句? 其实,【cin » str】作为while的条件表达式的解答过程是这样的:
第一,解“»”操作符,从cin关联的缓冲区中读取值(直到遇到空白、文件结束符EOF、错误时停止),如果读取则放入字符串str中,如果读取失败,即遇到文件结束符 EOF、错误时停止输入,并设置相应的流状态标记。
第二,无论解“»”操作符函数结果如何,都将返回cin。
第三,最迷茫的是返回的cin对象是如何作while条件表达式的?有说法调用了iOS的bool类型转换函数,将cin对象转换成一个bool值。其实这种解释我个人觉得也不对,在cppreference中个如下的标准库函数帮助文档:
红线代表的这个是将cin转换bool表达式的类型转换函数原型,但从“since C++11”看,这个函数从c++11才有的,在此之前C++标准库并没有这个函数。
其实,不知道到有没有人看到上面这个函数:
“while(cin»str)”就是通过这个类型转换函数实现的,当使用“while(cin»str)”这个表达时,编译器将自动执行“从类类型转换”,将cin转换成一个void *类型的指针的。在cplusplus有关于这个标准库转换函数的描述:
解释:此函数从ios(istream父类)类继承而来的类型转换函数,并能将一个流对象转换成一个指针;如果流对象的状态标记,(failbit orbadbit)两个标记中的一个被设置,流对象转换的指针将是一个空指针,否则就是一个非0指针”,并且,此类型转换函数也是唯一的从ios父类继承的非explicit从类类型转换函数。
将cin转换成指针类型了就当然可以作为while的条件表达式了,通过C++的标准转换,空指针转换成bool类型的false,非空指针将转换成bool类型的true,这样就能成功判断流的状态了。
-
当“cin»str”读流操作是成功的,流的状态标记(failbit orbadbit)就不会被设置,
-
cin执行“void*”类型转换函数转换而成的指针就非空,非空指针转换的bool就为true;
-
“cin»str”读流操作是失败的,流的状态标记(failbit orbadbit )就会被设置,
-
cin执行“void*”类型转换函数转换而成的指针就为空,空指针转换的bool就为false。
所以,“cin » str"就能作为合法的条件表达式置于while中。
getline,cin,scanf函数都是面向流的函数,它们的原理同上,不多赘述。
结束方法
cin是终端输入,也被称之为标准输入(standard input),cin的主要功能就是从标准输入读入一个值。
当从键盘上输入一串字符并按回车后,这些字符会首先被送到输入缓冲区中存储。每当按下回车键后,cin.get() 就会检测输入缓冲区中是否有了可读的数据。cin.get() 还会对键盘上是否有作为流结束标志的 Ctrl+Z 或者 Ctrl+D 键按下作出检查。其检查的方式有两种:阻塞式以及非阻塞式。
-
阻塞式检查方式指的是只有在回车键按下之后才对此前是否有 Ctrl+Z 组合键按下进行检查;
-
非阻塞式样指的是按下 Ctrl+D 之后立即响应的方式。
如果在按 Ctrl+D 之前已经从键盘输入了字符,则 Ctrl+D的作用就相当于回车,即把这些字符送到输入缓冲区供读取使用,此时Ctrl+D不再起流结束符的作用。如果按 Ctrl+D 之前没有任何键盘输入,则 Ctrl+D 就是流结束的信号。
Windows系统中一般采用阻塞式检查 Ctrl+Z、Unix/linux系统下一般采用非阻塞式的检查 Ctrl+D。这种阻塞式的方式有一个特点:只有按下回车之后才有可能检测在此之前是否有Ctrl+Z按下。还有一个特点就是:如果输入缓冲区中有可读的数据则不会检测Ctrl+Z(因为有要读的数据,还不能认为到了流的末尾)。还有一点需要知道:Ctrl+Z产生的不是一个普通的ASCII码值,也就是说它产生的不是一个字符,所以不会跟其它从键盘上输入的字符一样能够存放在输入缓冲区。
例:从键盘上输入abcd^z 加 回车之后在Windows系统上是这样处理的:由于回车的作用,前面的 abcd 等字符被送到输入缓冲区(注意:上面说过了,^z不会产生字符,所以更不会存储到输入缓冲区,缓冲区中没有 ^z 的存在)。这时,cin.get() 检测到输入缓冲区中已经有数据存在(因此不再检查是否有 ^z 的输入),于是从缓冲中读取相应的数据。如果都读取完了,则输入缓冲区重新变为空,cin.get() 等待新的输入。可见,尽管有 ^z 按下,但是由于在此之前还有其它输入字符(abcd),所以流也不会结束。因此,输入流结束的条件就是:^z 之前不能有任何字符输入(回车除外),否则 ^z 起不到流结束的作用。
文章作者 Forz
上次更新 2017-07-13