整个夏天我一直在使用“加速 C++”来学习 C++,并且有一个我似乎没有正确理解的概念。
为什么是
int x;
if (cin >> x){}
相当于
cin >> x;
if (cin){}
通过查看代码,在我看来,我们使用 cin 作为变量。但是,我认为这是一个功能。当 x 具有我们输入到键盘的任何值时,为什么我们可以以这种方式使用 cin?
整个夏天我一直在使用“加速 C++”来学习 C++,并且有一个我似乎没有正确理解的概念。
为什么是
int x;
if (cin >> x){}
相当于
cin >> x;
if (cin){}
通过查看代码,在我看来,我们使用 cin 作为变量。但是,我认为这是一个功能。当 x 具有我们输入到键盘的任何值时,为什么我们可以以这种方式使用 cin?
cin
istream
是表示标准输入流的类对象。它对应于cstdio
流stdin
。流的运算符>>
重载返回对同一流的引用。流本身可以通过转换运算符在布尔条件下评估为真或假。
cin
提供格式化的流提取。操作
cin >> x;
如果输入非数字值,其中 "x" 是 int 将失败。所以:
if(cin>>x)
false
如果您输入字母而不是数字,将返回。
这个关于使用 C++ I/O 的技巧和窍门的网站也会对您有所帮助。
注意:答案在事实发生四年后更新,以解决 C++98/03 和 C++11(及更高版本)。
std::cin
是 a 的一个实例std::istream
。该类提供了与此问题相关的两个重载。
operator >>
如果可能,将数据从流中读取到目标变量中。如果流的直接内容不能转换为目标变量的类型,则流被标记为无效并且目标变量保持不变。无论操作成功/失败,返回值都是对流的引用。operator void*()
将流引用转换为指针的(C++11 之前的)void*
或explicit operator bool()
将流引用转换为布尔值的(C++11)。true
如果流有效,则此转换的结果是非空指针 (pre-C++11) 或(C++11),但空指针 (pre-C++11) 或false
(C++11 ) 如果流无效。语句需要if
布尔值、整数或指针作为要测试的量。的结果std::cin >> x
是对 an 的引用istream
,这不是上述内容。但是,该类istream
确实具有那些可用于将istream
引用转换为if
语句中可用内容的转换运算符。它是语言用于if
测试的特定于版本的转换运算符。由于读取失败会将流标记为无效,因此if
如果读取失败,则测试将失败。
在 C++11 之前使用更复杂的转换成员的原因operator void*
是,直到 C++11 才将已经存在的explicit
关键字扩展为适用于转换运算符和构造函数。一个非显式的operator bool()
代码会给程序员提供太多的机会让他们自爆。也有问题operator void*()
。“安全布尔成语”本来可以解决问题,但只需扩展即可explicit
完成安全布尔成语所完成的工作,而无需使用大量 SFINAE 魔法。
cin
是类型的(全局)变量istream
,而不是函数。
该类istream
覆盖>>
操作符以执行输入并返回对您调用它的对象的引用 ( cin
)。
cin
在命名空间中是变量std
。
operator>>
返回对 的引用cin
,因此您可以编写: cin >> a >> b
,而不是cin >> a; cin >> b;
上面的答案是有益的。在这里,我只是提供一个额外的评论。
std::cin
是 class 的一个对象,istream
代表C流中对应的标准输入流(即键盘) 。 stdin
cin >> x
将首先从标准输入流中读取一个 int 并将其分配给x
. 之后返回对cin
. 所以函数调用的返回值cin >> x
仍然是cin
.
所以从if 条件来看,if(cin)
和if(cin >> x)
彼此相似。标准IO 库为这样的流定义了一个函数(取决于实现):
explicit operator bool() const; // C++11
或者
operator void*() const; //C++98, C++2003
从这两个声明中,我们知道它们直接或间接地(通过pinter很明显)将流类型转换为类型。void*
bool
bool
在这两个函数中,它们依赖于一些基本的IO 流状态(类字段)来确定返回 false 还是 true(对于void*
case,它是nullptr
与否)。
cin
是一个类的实例,istream
它继承了cast-to-bool函数。所以它有效!
因为表达式的结果
cin >> x
评估为
cin
在读取流之后。
1)cin
是 的一个实例istream
,请参见http://www.cplusplus.com/reference/iostream/cin/。
2) 的>>
运算符istream
将返回其左操作数,在这种情况下为cin
,请参见http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/。failbit
如果没有从 中提取字符,则此运算符将设置为 on cin
,以防阅读器已完成EOF
,因此将不再有要阅读的字符。
3)如上2),在读取操作后评估条件时,if (cin >> x)
应该是这样if (cin)
的,参考这个链接http://www.cplusplus.com/reference/ios/ios/operator_bool/你会看到,此if
块将返回:
如果至少设置了failbit
or之一,badbit
则为空指针。其他一些值(对于 C++98 标准)。
如果设置了这些错误标志中的至少一个,则该函数返回 false,否则返回 true。(对于 C++11 标准)
std::cin
是std::istream
类的一个实例。
cin >> x
只是在cin
对象上调用一个函数。您可以直接调用该函数:
cin.operator >>(x);
为了允许您一次读取多个变量,该operator >>
函数返回对调用它的流的引用。您可以致电:
cin >> x >> y;
或等效地:
cin.operator >>(x).operator >>(y);
或者:
std::istream& stream = cin.operator >>(x);
stream.operator >>(y);
难题的最后一部分std::istream
是可转换为bool
. bool 相当于调用!fail()
.
所以在下面的代码中:
int x;
std::istream& stream = std::cin.operator >>(x);
bool readOK = !stream.fail();
if (readOK)
{
std::cout << x << "\n";
}
bool readOK = !stream.fail();
可以归结为刚刚bool readOK = stream;
。
您不需要单独bool
存储流状态,因此可以这样做if (stream)
。
删除临时stream
变量给出if (std::cin.operator >>(x))
.
直接使用运算符让我们回到原始代码:
int x;
if (std::cin >> x)
{
std::cout << x << "\n";
}
因为 cin 是类的对象,请在http://www.cplusplus.com/reference/iostream/cin/上阅读更多内容。