之前在学 C++ 的时候,第一个例子大概是:
1 |
|
当时也没多想,std 这个东西是什么。后来在接触了其它库后,发现也需要 std 的配合使用,如 std::sort()。今日来仔细研究下名称空间这个东西。
先掏出 cplusplus.com 来看看 <iostream> 是什么东西,官方的定义如下:
Header that defines the standard input/output stream objects. After C++11, including
<iostream>automatically includes also<ios>,<streambuf>,<istream>,<ostream>and<iosfwd>.
而对于 std 而言,std 是一个名称空间,:: 是作用域解析运算符,std::cout 的意思就是使用 std 名称空间中的 cout 标识符,也就是这个对象。而这个对象的定义在 <iostream> 这个标准库文件中,所以要包含这个头文件,才能使用 cout 这个对象。
除此之外,C++ 标准库中的函数或对象都是在名称空间 std 中定义的,所以我们要使用标准函数库中的函数或对象都要使用 std 来限定。所以使用 cout 的时候要加上 std:: 时,编译器就会明白我们调用的 cout 是名字空间 std中的 cout,而不是其它名称空间中的 cout。
#include是预处理器编译指令,表示使用预处理器在主编译之前对源文件进行整理。这里并不需要任何指令调用预处理器,编译时自动调用执行。这里的意思就是将iostream文件中的内容添加到程序中,即合成为一个新文件。这里的用途就是,在源文件被编译之前,替换或添加文本,这也是典型的一种预处理器操作。using namespcec std是编译指令,如果是#include <xxx.h>则不需要using编译指令,因为老式的头文件没有使用名称空间。新头文件使用了std名称空间,标准库的类、函数、变量是 C++ 编译器的标准组件,被放到了std空间中。
但是,尽量不要使用 using namespace std,这句话的意思是告诉编辑器我们将要使用空间 std 中的函数或者对象。或者说,能不用就不用,能在大括号里面用就不要在外面用,尤其是在 .h 等头文件中。幻想一下,你写的 .h 文件被其它人使用,你的名字空间和他人的名字空间不一样,但名字空间下面的函数名一样,就会导致冲突。跟 python 中写 from numpy import * 一个道理。
自定义名称空间
名称空间提供了一个声明名称的区域,而可以通过作用域解析运算符 :: 访问其中的名称。如下是一种简单的写法:
1 | // mylib/show_info.h 文件下 |
using 声明与编译指令
有的时候并不希望每次使用名称时都进行限定,所以 C++ 提供了两种机制,using 声明使得特定的名称可用,using 编译指令使名称空间中的所有名称可用,两者都可以简化名称空间中名称的使用,也都会增加名称冲突的可能性。
对于 using 声明而言,将指定的的名称添加到声明区域,使其可用。如下所示的代码:
- 在声明的作用域内,不能在声明其它同名变量;
- 屏蔽全局同名变量。除用户定义的名称空间外,还存在一个全局名称空间,全局变量在这里面。同
C++的局部变量会屏蔽全局变量一样,名称空间也是如此,但两个名称空间中的同名变量并不会冲突。
1 |
|
对于 using 编译指令而言,会使所有名称可用,包括可能不会使用的名称。如下所示的代码:
test::a位于局部名称空间,不会影响全局变量;- 局部同名变量会屏蔽名称空间里的变量和全局变量。
1 |
|
总结一下就是,当名称空间和声明区域定义了相同的名称:
using声明导入时,会冲突;using编译指令导入时,局部名称会屏蔽名称空间里面的名称,且没有警告。
因此,使用 using 声明会更加安全,编译指令可能会掩盖一些同名变量。此外,还有一些其它要注意的点:
- 名称空间可以嵌套,但最好加上限定,表明这个名称的来源;
- 以函数为例,名称空间里面的函数的声明和定义要在同一名称空间内;
- 如果函数被重载,那么一个
using声明将导入所有版本; 对于未命名的名称空间,不能显式使用
using,不能在名称空间之外的文件使用名称空间中的名称。这可以作为链接性为内部静态变量的替代品。1
2
3
4
5
6
7
8
9
10
11
12
namespace {
int a = 100;
int b;
};
int main (){
// 名称空间中的 a
std::cout << a << std::endl;
return 0;
}当名称空间很长时,可以简化名称空间:
1
2namespace MEF = math::element::fire;
using MEF::flame;