关于 C++中 while(cin &gt&gt a) 的解释 和 operator void*() 和 bool operator!()的理解

做题的时候,我经常用while(cin>>a)这样的模式来  实现 连续输入 或 统计输入连续数字的个数 等功能,但是一直都对其中的原理感到迷迷糊糊,我觉得只会用怎么行,还得搞明白 其所以然 来。所以看了一些资料和大佬们的博客,然后写这样一篇博客来解释其中的原理。


 

使用情形 以及 跳出的while(cin>>a)的方法

while(cin>>a)的意思是 只要输入的值有效,那么就执行while体内的语句。while循环结束 (跳出流对象)的时候 ,通过检测其流的状态来判断结束:
(1)若流是有效的,即流未遇到错误,那么检测成功。
(2)若遇到一个无效的输入时(例如:上述的a是int类型的,但输入的值不是一个整数),istream对象的状态会变为无效,条件就为假。
(3)若遇到文件结束符也可以跳出while(cin>>a)。在windows系统中,输入文件结束符的方法是先按Ctrl+Z,然后再按Enter。在UNIX系统中,包括Mac OS X系统中,文件结束输入为Ctrl+D。
  特别的:在while循环中以EOF作为文件结束标志(end of file),EOF是针对文件输入的情况,文件指针如果指向文件尾就会等于EOF。 这种以EOF作为文件结束标志的文件,必须是文本文件!在文本文件中,数据都是以字符ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~127,不可能出现-1,因此可以用EOF作为文件结束标志。
   




原理剖析

跳不跳出while(cin>>a)循环 关键在于 cin>>a 的值 是不是 假(0)。

运算符返回的是流对象的引用,cin是一个流对象,而>>运算符返回左边的流对象,也就是说cin>>val返回cin,于是while(cin>>val)就变成了while(cin),问题就变成了一个流对象在判断语句中的合法性。 (注意一下:右移运算符>>的结合方向是从左到右 输入流类(istream) 把 >> 重载了)

如果定义了一个类(没有重载  void * 和 ! 运算符的类),然后定义该类的对象,然后使用 while 或者 if 语句来判断它是不合法的。可是为什么while(cin) 和 if(cin)都是合法的呢?原来 输入流类(istream) 重载了 void*  ! 这两个运算符!!

打开iostream.h文件,可以看到 operator void *() const和bool operator!() const 这两个函数。这两个函数使得流对象可作为判断语句的内容。

可是重载这两个运算符 跟可作为判断语句的内容有什么关系?

原因是这样的:
(以下用if来解释,其实while和if 在处理这方面的情况是一样的)
①先来测试下没有重载上述运算符的情况

#include <iostream>
using namespace std;
class A
{
	
};

int main()
{
    A a;
    if(a)
        cout<<"YES";
    
    return 0;
}

不出所料,报错信息如下:

[Error] could not convert 'a' from 'A' to 'bool'

分析:说明编译器编译的时候 不能 将对象a转换为bool类型,不能转换的话 也就无法判断if里判断语句的内容是 真(非0) 是 假(0) 了。


①改进:重载了void*后

#include <iostream>
using namespace std;
class A
{
public:
	//返回值类型 就是void* 不用额外写 
    operator void*() 
    {
        return (void*)0;
    }
};

int main()
{
    A a;
    if(a)
        cout<<"YES";
    
    return 0;
}

分析:这样写后,编译就没问题了。
因为在a不能直接转换为bool类型的情况下,会试图先进行 (void*)a 这样的操作,这个操作会直接调用A类的成员函数operator void*(),这个函数返回一个void*的数据,所以这里的if(a)其实就是if((void*)a),然后根据强制转换后的结果来进行if的判断,这里显然应该不输出。如果改成return (void*)this,那么就可以看到运行后输出了YES


②然后来看看下面的代码

#include <iostream>
using namespace std;
class A
{
public:
	//返回值类型 就是void* 不用额外写 
    operator void*() 
    {
        cout<<"a";
        return (void*)0;
    }
};

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

输出:aYes

分析:当程序执行到if(!a)时,对于!a,同样是由于a无法直接转化为bool类型,所以!a就等同于!((void*)a),由于(void*)a的值为0 (调用了A类的成员函数operator void*(),然后返回了(void*)0 ),所以!a为真,那么就可以执行if(!a)里面的语句了。


②改进:重载了 ! 运算符

#include <iostream>
using namespace std;
class A
{
public:
	//返回值类型 就是void* 不用额外写 
    operator void*() 
    {
        cout<<"a";
        return (void*)0;
    }
    
    bool operator!()
    {
    	cout<<"A";
    	return true;
    }
};

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

输出:AYes

分析:重载了运算符!后, !a就直接执行了operator!()函数,该函数返回true,所以可以执行if(!a)里面的语句。

好的,这是一个经典的搜索问题,下面是一个用C++实现的A*算法解决八数码难题的示例代码: ```c++ #include <iostream&gt; #include <cstring&gt; #include <algorithm&gt; #include <queue&gt; using namespace std; const int MAXN = 1e5; const int INF = 0x3f3f3f3f; struct node{ int a[3][3], f, g, h; bool operator < (const node &rhs) const { return f &gt; rhs.f; } }; int dx[] = {-1, 0, 1, 0}; int dy[] = {0, 1, 0, -1}; int h(node u){ int res = 0; for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ if(u.a[i][j] == 0) continue; res += abs(i - (u.a[i][j] - 1) / 3) + abs(j - (u.a[i][j] - 1) % 3); } } return res; } bool check(node u){ int cnt = 0; for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ for(int k = 0; k < i; k++){ for(int l = 0; l < 3; l++){ if(u.a[i][j] == u.a[k][l] && u.a[i][j] != 0) cnt++; } } } } if(cnt % 2 == 0) return true; else return false; } node start, goal; int vis[MAXN], fa[MAXN]; void print(node u){ if(fa[u.f] == -1) return; print(fa[u.f]); for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ cout << u.a[i][j] << " "; } cout << endl; } cout << endl; } int Astar(){ memset(vis, 0, sizeof(vis)); memset(fa, -1, sizeof(fa)); priority_queue<node&gt; q; start.f = h(start); start.g = 0; start.h = h(start); q.push(start); while(!q.empty()){ node u = q.top(); q.pop(); if(vis[u.f]) continue; vis[u.f] = 1; if(u.f == goal.f){ print(u); return u.g; } for(int k = 0; k < 4; k++){ int nx = dx[k] + (u.a[0][0] == 0 ? 1 : 0), ny = dy[k] + (u.a[0][0] == 0 ? 1 : 0); if(nx &gt;= 0 && nx < 3 && ny &gt;= 0 && ny < 3){ node v = u; swap(v.a[nx][ny], v.a[0][0]); v.f = v.g + h(v); v.g++; if(!vis[v.f]){ fa[v.f] = u.f; q.push(v); } } } } return -1; } int main(){ for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ cin &gt;&gt; start.a[i][j]; if(start.a[i][j] == 0) start.a[i][j] = 9; } } for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ cin &gt;&gt; goal.a[i][j]; if(goal.a[i][j] == 0) goal.a[i][j] = 9; } } start.f = h(start); goal.f = h(goal); if(!check(start) || !check(goal)){ cout << "No solution" << endl; return 0; } int res = Astar(); if(res == -1) cout << "No solution" << endl; else cout << res << endl; return 0; } ``` 这段代码实现了八数码难题的A*算法搜索,其h函数用于计算状态u到目标状态goal的估价函数值,check函数用于判断初始状态和目标状态是否能够到达,print函数用于输出最短路径,Astar函数用于实现A*算法搜索,主函数首先读入初始状态和目标状态,然后进行一些必要的初始化,最后调用Astar函数进行搜索。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

重剑DS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值