• 为什么可以用while(cin)?


    为什么可以用while(cin)?

     
    复制代码
    /**
     *  @brief  The quick-and-easy status check.
     *
     *  This allows you to write constructs such as
     *  "if (!a_stream) ..." and "while (a_stream) ..."
    */
    operator void*() const
    { return this->fail() ? 0 : const_cast<basic_ios*>(this); }
    复制代码

    如果你把一个basic_ios类的对象(cin就是)放到if语句的括号里,它就会被转换成void*型。如果输入失败的话,就会得到一个空指针(也就是0),那么if语句就不能通过。

    复制代码
    #include<iostream>
    #include<utility>
    using namespace std;
    int main()
    {
       int i;
       do
      { cout<<i<<endl; }while(cin>>i); }
    复制代码

    首先输出个0.之后输入X,输出X;当输入ctrl+d时,没有输出,结束。

    复制代码
    #include<iostream>
    #include<utility>
    using namespace std;
    int main()
    {
       int i;
       do{
          cin>>i;
          cout<<i<<endl; 
    
       }while(cin); 
    }
    复制代码

    输入x,输出x;当输入ctrl+d时,再输出个上一次的输入量,结束。

    ctrl+d表示表示输入错误。

    cin.clear()可以重新将cin置为有效。

    导致循环终止的原因是流对象cin进入错误状态:系统输入级故障;读入了无效数据;遇到文件结束符。

    下面是一个用到cin判断作为循环条件的程序:

    复制代码
    #include<iostream>
    #include<utility>
    #include<vector>
    #include<map>
    using namespace std;
    int main()
    {
       map<string,vector< pair<string,string> > > family;
       pair<string,string> pa;
       string surName,childName,birthDate;
       do{
          cout<<"enter surname"<<endl;
          cin>>surName;
          if(!cin)
         break;                     //如果cin无效,跳出循环
          vector< pair<string,string> > child;
          pair<map<string,vector<pair<string,string> > >::iterator,bool>
          ret = family.insert(make_pair(surName,child));
          cout<<"input name and age"<<endl;
          while(cin>>surName>>birthDate)
          {
             pair<string,string> pa;
             pa = make_pair(surName,birthDate);
             ret.first->second.push_back(pa);     //ctrl+d跳出循环,此时cin无效
          }
          cin.clear();           //使cin重新有效,以达到下面while循环条件。
       }while(cin);
       cout<<"enter search"<<endl;
       cin.clear();
       cin>>surName;
       map<string,vector< pair<string,string> > >::iterator it = family.find(surName);
       if(it==family.end())
       cout<<"no this surname"<<endl;
       else
       {
       vector< pair<string,string> >::iterator itt = it->second.begin();
       while(itt!=it->second.end())
          {
          cout<<(*itt).first<<"		"<<(*itt).second<<endl;
          itt++;
          }
       }
       return 0;
    }
    复制代码

    while(cin)和while(!cin)的原理分析

    今天看书的时候看到代码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类型。

              C++中basic_ios.h中的函数定义如下:

    [cpp] view plaincopy
     
    1. /** 
    2.  *  @brief  The quick-and-easy status check. 
    3.  * 
    4.  *  This allows you to write constructs such as 
    5.  *  "if (!a_stream) ..." and "while (a_stream) ..." 
    6. */  
    7. operator void*() const  
    8. return this->fail() ? 0 : const_cast<basic_ios*>(this); }  
    [cpp] view plaincopy
     
    1. bool operator!() const  
    2. return this->fail(); }  


            因此,可以简单的理解调用过程为:

                   while(cin)  =====> while(!cin.fail())              //while the stream is OK
                   while(!cin) =====> while(cin.fail())               //while the stream is NOT OK

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

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

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

    [cpp] view plaincopy
     
     
    1. #include<iostream>  
    2. using namespace std;  
    3. class A  
    4. {  
    5. public:  
    6.     A(){}  
    7.     ~A(){}  
    8.     operator void *()const  
    9.     {  
    10.         cout<<"cast to void*; ";  
    11.         return (void *)this;  
    12.     }  
    13.      bool operator!() const  
    14.     {  
    15.         cout<<"cast to bool; ";  
    16.         return true;  
    17.     }  
    18. };  
    19.   
    20. int main()  
    21. {  
    22.     A a;  
    23.     if(a) cout<<"first"<<endl;  
    24.     if(!a) cout<<"second"<<endl;  
    25.     return 0;  
    26. }  

            运行以上程序,结果为cast to void*; first和cast to bool; second。结果表明,if(a)隐式调用了operator void *()函数,if(!a)隐式调用了bool operator!()函数。

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

  • 相关阅读:
    linux平台下Hadoop下载、安装、配置
    C#实现单例,保证线程安全
    编写response生成图片验证码时,报import com.sun.image.codec.jpeg.JPEGCodec;
    Java中static是什么意思,有什么作用?
    使用内部类和闭包
    在数据结构中存储对象
    Java学习——响应用户输入
    提升代码质量——结构化编程
    各种排序总结(六)归并排序
    各种排序总结(五)快速排序
  • 原文地址:https://www.cnblogs.com/yymn/p/5103547.html
Copyright © 2020-2023  润新知