1.3a初识cout、cin与名称空间

std::cout

如前面章节所提,std::cout可以用来向控制台输出文本,看下面的Hello World程序回忆一下。

#include <iostream>

int main()
{
    std::cout << "Hello world!";
    return 0;
}

为了实现在一行输出多个内容,输出操作符<<可以被使用多次,例如:

#include <iostream>

int main()
{
    int x = 4;
    std::cout << "x is equal to: " << x;
    return 0;
}

程序输出:

x is equal to: 4

猜一下下面这个程序输出什么?

#include <iostream>

int main()
{
    std::cout << "Hi!";
    std::cout << "My name is Alex.";
    return 0;
}

你可能会对结果感到惊讶:

Hi!My name is Alex.

std::endl

如果你想将内容打印在不同行,可以使用std::endl(注:endl可以看成英文end line,意为结束这一行,所以endl可以看作换行符或者一行的结束符),这将会插入一个换行符,导致光标移动到下一行开头。例如:

#include <iostream>

int main()
{
    std::cout << "Hi!" << std::endl;
    std::cout << "My name is Alex." << std::endl;
    return 0;
}

输出结果是:

Hi!

My name is Alex.

std::cin

std::cout对应的是std::cin – std::cout使用输出操作符<<将数据打印到控制台上,std::cin则使用输入操作符>>从用户处读取键盘输入。现在你已经对变量有了基础认知,我们可以使用std::cin从用户处读取输入并将其存储到一个变量中。

#include <iostream>

int main()
{
    std::cout << "Enter a number: "; // 要求用户输入一数字
    int x = 0;
    std::cin >> x; // 从控制台读取数字并存储到x中
    std::cout << "You entered " << x << std::endl;
    return 0;
}

试着亲自编译并运行这个程序,你会看到屏幕上先显示“Enter a number: ”,然后等待你键入数字,等你输完数字(并按回车键结束后),就会打印出“You entered …(你输入的数字)”,例如我输入4:

Enter a number: 4

You entered 4

这是获取用户输入的一个简单方法,后面我们还会多次用到。如果你输入数字后窗口迅速关闭,请参看《0.7 常见C++问题解答》

(趣事:如果你输入一个特别大的数字,结果可能会令你大吃一惊,试一下,出现这个情况的原因是x只能存储一个特定大小的数,超过那个数后,就会“溢出”,后续的章节中我们会讨论到溢出。)

std::cin,std::cout,<<和> >

初学者经常混淆std::cin,std::cout,<<和> > 。这里有一个简单的方法帮助你记忆:

  • std::cin,std::cout总是在语句的左边。
  • std::cout用来输出一个值(cout =output)。
  • std::cin用来获取一个输入值(cin =input)。
  • <<跟随std::cout使用,表明数据的流动方向是从左值到控制台。std::cout << 4表示将4移动到控制台。
  • >>跟随std::cin使用,表明数据的流动方向是从控制台到变量。std::cin > > x表示数据从控制台流动到X。

名称空间

标准库中的一切都定义在一个称为std(standard的缩写)的特殊区域(称为名称空间,也译作命名空间)中。

原来,std::cout的真名并非“std::cout”,而是“cout”,而“std”是它“生活”空间的名字。

未来我们会花更多时间讨论名称空间并教你创建一个自己的名称空间。现在我们只需要记住无论什么时候使用标准库中的东西,都需要告诉编译器它在std名称空间中。

使用std::访问名称空间

告诉编译器cout在std名称空间中的一种方式是使用std::前缀,例如:

std::cout << “Hello world!”;

这是使用cout最安全的方式,因为这样没有任何歧义,明确地指出了cout存在的名称空间。但是,如果你需要大量使用标准库中的东西,每次都输入std::显然是件麻烦事,C++提供了两种方法来简化这个问题。

using声明

简化的方法之一是使用using声明语句,例如:

#include <iostream>

int main()
{
   using std::cout; // using语句声明了cout存在于std空间中
   cout << "Hello world!"; // 所以此处无需再添加前缀std::
   return 0;
}

using声明语句告诉编译器我们将会使用std中的cout,所以每次它看到cout的时候,就会想到我们的意思是”std::cout”,如果std::cout与其他名称空间(假设存在)中的cout存在命名冲突,那么std::cout将会是优先选择,所以在cout << “Hello world!”;中,我们可以直接使用cout。

在这份教程的例子中这并不会帮你节省多少精力,但是如果你在一个函数中大量使用cout,使用using语句将会大大增加你程序的可读性。需要注意的是每一个名字都需要有一个单独的using声明,比如using std::cout;  using std::cin;  using std::endl;。

尽管这种方式没有使用”std::”前缀明确,但通常被认为是安全的、可接受的。

using编译指令

另一种简化方法是使用using编译指令语句,例如:

#include <iostream>

int main()
{
   using namespace std; // using编译指令告诉编译器我们将使用std中的所有名称
   cout << "Hello world!"; // 所以此处无需std::前缀
   return 0;
}

using编译指令”using namespace std;”告诉编译器我们想使用std空间中的所有名称,所以当编译器发现一个不认识的名称时,就会去检索std空间。所以当编译器遇到陌生的cout时,就会去std中检索,但如果发生命名冲突,编译器就会报错。

关于这个解决方案的好坏曾有过公开辩论。using编译指令使用命名空间中的所有的名称,命名冲突的机会上升显著(但仍然是比较小的)。

在函数内部或外部使用using声明与编译指令

如果在函数内部使用using声明或编译指令,名称空间中的名称就只能在该函数中访问,这减少了函数中发生命名冲突的几率。但是,如果在函数外使用using声明或编译指令,那么名称空间中的名称可以在整个文件中访问,这就大大增加了冲突发生的可能性。(通过之后的学习会对此有进一步认识,此处仅仅了解一下。)

冲突举例

为了更好的说明上述问题,我们来举一个使用using编译指令产生命名冲突的例子。

#include <iostream>

int cout() // 声明了我们自己定义的"cout"函数
{
    return 5;
}

int main()
{
    using namespace std;
    cout << "Hello, world!"; //疑惑,此处指的是哪个cout呢?
    return 0;
}

上述例子中,编译器无法确定cout究竟是std中的cout还是我们自己定义的cout,将会产生一个”ambiguous symbol(不明确的符号)”编译错误。如果我们使用using声明或者std::前缀,就不会存在这个问题。比如:

std::cout << "Hello, world!";

或者:

using std::cout;
cout << "Hello, world!";

这样我们的程序就不会有问题了。

许多人避免使用using编译指令就是出于这个原因,有些人也发现只在个人定义的函数中使用它是可以接受的(这样限制了命名冲突只可能发生在函数中)。

使用using语句的注意事项

除了本节的例子,我们都会使用限定的名称(qualified name,即有例如std::前缀的名称),个别情况下为了程序可读性,我们会在函数中使用using编译指令,是否遵循这个规则取决于你自己,你也可以完全避免使用using语句。

规则:任何情况下,都应当避免在函数体外使用using语句。

转载请参看关于博客页面相关要求。

关于 “1.3a初识cout、cin与名称空间” 的 1 个意见

评论关闭。