while(cin>>val)的调用机理

今天看书的时候看到代码while(cin>>val),忽然就在想这样写的合法性是如何判定的。我们都知道cin是一个流对象,而>>运算符返回左边的流对象,也就是说cin>>val返回cin,于是while(cin>>val)就变成了while(cin),问题就变成了一个流对象在判断语句中的合法性。

不管是while(cin)还是if(cin),都是合法的,为什么呢?我们自己定义一个类,然后定义该类的对象,然后使用if语句来判断它是不合法的。这说明,流对象具有某种转换函数,可以将一个流对象转换成判断语句可以识别的类型。

经过在网上的搜索查询发现,流对象确实存在这样的转换。

打开iostream.h文件,找到cin的定义,发现是来自于istream.h,其中的模板类basic_istream继承自basic_ios,打开basic_ios的定义,发现它继承自ios_base,再次定位到ios_base类,发现它有两个重载函数。operator void *() const和bool operator!() const。这两个函数使得流对象可作为判断语句的内容。(参考网页)

operator void *() const;函数在while(cin)或是if(cin)时被调用,将流对象转换成void*类型。

bool operator!() const;函数在while(!cin)或是if(!cin)时被调用,将流对象转换成bool类型。

///当流处于goodbit状态时,读入成功码,返回cin地址,并转换为void*型,继续循环
operator void* () const
{
    ///流的状态由>>操作符调用ios改变,当读到eof或者输入不符合所写入的类型时设置badbit和failbit
    if (state & (badbit | failbit)) ///一种直观的写法
        return 0;///当流处于badbit或failbit状态时,返回0,循环停止
    return (void*)this;///返回的是cin,相当于while(cin)
}

查看本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/

需要指出的是,上述两个类型转换都是隐式的。

既然我们找到了while(cin)合法的原因,自然需要试验一下。

我们定义一个类A,在A中定义上述两个函数,然后定义A的一个对象a,使用if(a)和if(!a)来验证一下。代码如下:

#include<iostream>
using namespace std;  

class A
{
    public:
        A() {}
        ~A() {}
        operator void* () const
        {
            cout << "cast to void*; ";
            return (void *)this;
        }
        bool operator ! () const
        {
            cout << "cast to bool; ";
            return true;
        }
};  

int main()
{
    A a;
    if (a) cout << "first" << endl;
    if (!a) cout << "second" << endl;
    return 0;
}

运行以上程序,结果为cast to void*; first和cast to bool; second。

结果表明,if(a)隐式调用了operator void* ()函数,if(!a)隐式调用了bool operator ! ()函数。

上述两个函数其实是操作符的重载过程。使用这种重载函数,我们就可以像使用cin一样,用if语句对我们的对象做判断了。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索对象
, 函数
, bool型函数定义非法
, cout 输出流
, while
, cin
, operator
, 句子 cin
, 一个
流状态
cin、while cin 结束、while cin eof、while cin s、c while cin,以便于您获取更多的相关知识。

时间: 2024-09-16 17:42:58

while(cin&gt;&gt;val)的调用机理的相关文章

javascript 循环调用示例介绍_javascript技巧

复制代码 代码如下: function checksdzt(){ sdzt = $("#viewObj_zt_text").val(); //循环调用,如果已经获取到了结果,则退出循环 loopgetinfo = setInterval("checksdztsub()",50); //这里循环调用,间隔50毫秒 } function checksdztsub(){ if ($("#viewObj_zt_text").val() !="&

如何使用GDB调试PHP程序_php实例

一般来说,GDB主要完成下面四个方面的功能: (1)启动你的程序,可以按照你的自定义的要求随心所欲的运行程序. (2)可让被调试的程序在你所指定的调置的断点处停住.(断点可以是条件表达式) (3)当程序被停住时,可以检查此时你的程序中所发生的事. (4)动态的改变你程序的执行环境. 1.简介 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.如果你是在 UNIX平台下做软件,你会发现GDB这个调试工具有比VC.BCB的图形化调试器更强大的功能.同时GDB也具有例如ddd这样的图形化

COM编程入门第二部分——深入COM服务器

本文为刚刚接触COM的程序员提供编程指南,解释COM服务器内幕以及如何用C++编写自己的接口.继上一篇COM编程入门之后,本文将讨论有关 COM服务器的内容,解释编写自己的COM接口和COM服务器所需要的步骤和知识,以及详细讨论当COM库对COM服务器进行调用时,COM服务器运行的 内部机制. 如果你读过上一篇文章.应该很熟悉COM客户端是怎么会事了.本文将讨论COM的另一端--COM服务器.内容包括如何用C++编写一个简单的不涉及 类库的COM服务器.深入到创建COM服务器的内部过程,毫无遮掩

第九章 方法[《.net框架程序设计》读书笔记]

.net框架|笔记|程序|设计 第九章 方法 一. 实例构造器 1. 前面提到用new操作符创建对象时的三部曲: l 为对象分配内存 l 初始化对象的附加成员(方法表指针和SyncBlockIndex) l 调用实例构造器初始化实例状态 在分配内存时,系统将所有内存位置均置为0值,这就是为什么字段初始化而未赋值时均为0或null值. 不调用实例构造器的情况: l 调用Object.MemberwiseClone()方法创建实例(分配内存:初始化附加成员:将源对象字节拷贝到新创建的对象) l 反序

COM编程入门:深入COM服务器

本文为刚刚接触COM的程序员提供编程指南,解释COM服务器内幕以及如何用C++编写自己的接口. 继上一篇COM编程入门之后,本文将讨论有关COM服务器的内容,解释编写自己的COM接口和COM服务器所需要的步骤和知识,以及详细讨论当COM库对COM服务器进行调用时,COM服务器运行的内部机制. 如果你读过上一篇文章.应该很熟悉COM客户端是怎么会事了.本文将讨论COM的另一端--COM服务器.内容包括如何用C++编写一个简单的不涉及类库的COM服务器.深入到创建COM服务器的内部过程,毫无遮掩地研

下一代C++:C++/CLI语言的属性探索

前言: 本文展示了欧洲计算机开发商协会正在发展的C++/CLI(一种不同的C++语言,它方便开发人员在微软的.NET框架下更容易地开发程序)语言在C++语言上的扩展.写这篇文章的目的并不是要建议标准C++包括这部分扩展,也不是对C++/CLI的认可,而只是在探讨C++/CLI语言在这一领域的发展方向. 一.基础知识 C++/CLI中的属性是类似与各种数据成员(有各种操作限制)的可操作实体,但是这种操作往往被转化为调用存取函数(这主要是"getter"和"setter"

COM技术内幕(笔记)

COM--到底是什么?--COM标准的要点介绍,它被设计用来解决什么问题?基本元素的定义--COM术语以及这些术语的含义.使用和处理COM对象--如何创建.使用和销毁COM对象.基本接口--描述IUnknown基本接口及其方法. 掌握串的处理--在COM代码中如何处理串.应用COM技术--例子代码,举例说明本文所讨论的所有概念. 处理HRESULT--HRESULT类型描述,如何监测错误及成功代码. COM--到底是什么?     简单地说,COM是一种跨应用和语言共享二进制代码的方法.与C++

hdu 1106 排序

#include <iostream> #include <cstring> #include <algorithm> using namespace std; char str[1005]; int shu[1005];//存的是数 //1.有可能有好几个5; //2.有可能末尾是5; //3.有可能第一个是5; int main() { while(cin>>str) { int val=0,num=0; for(int i=0;str[i]!='\0'

Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析_Android

     在上一篇文章中,我们分析了Android系统进程间通信机制Binder中的Server在启动过程使用Service Manager的addService接口把自己添加到Service Manager守护过程中接受管理.在这一篇文章中,我们将深入到Binder驱动程序源代码去分析Client是如何通过Service Manager的getService接口中来获得Server远程接口的.Client只有获得了Server的远程接口之后,才能进一步调用Server提供的服务.