# 命名空间 大型程序往往会使用多个独立开发的库,这些库又会定义大量全局名字,如类、函数和模板等。当应用程序用到多个第三方类库时,不可避免地会发生某些命名相互冲突的情况。多个库将名字放置在全局命名空间中将引发命名空间污染。传统方式上,程序员会通过将其定义的全局实体名字设置得很长来避免命名空间名字冲突问题,这样得名字通常会包含名字所属库的前缀部分,如 `class cplusplus_primer_Query{...}` ,这种解决方案显然不好。 命名空间为防止名字冲突提供了很好的解决方案,命名空间分割了全局命名空间,其中每一个命名空间都是一个作用域。通过在某个命名空间中定义库的名字、库的作者(以及用户)可以避免全局名称固有的限制。 ## 命名空间 ### 定义 一个命名空间的定义分为两个部分:关键字 `namespace` 和命名空间的名字。在命名空间名字后面是大括号括起来的声明和定义。 ```c++ namespace cplusplus_primer { class SalesData {...}; } //命名空间结束后无需分号,与块类似。 ``` 每个命名空间都是一个作用域,不同的命名空间内名字相同是不同的作用域下的名字。命名空间可以是不连续的,同一个命名空间可以定义在几个不同的部分,这一点与其他作用域不同。每当我们编写一个命名空间: ```c++ namespace wang { ... } ``` 这个命名空间可能是新定义的命名空间`wang`,也可能是为已经存在的 `wang` 命名空间添加一些新的成员。正是由于这种不连续的特性,使得我们可以将几个独立的接口和实现文件组成一个命名空间。 ### 实例 通过使用命名空间,我们可以在几个不同的文件中定义一个统一的自己的库。 ```c++ //Sales_data.h #include namespace cplusplus_primer { class Sales_data {/*...*/}; Sales_data operator+(const Sales_data &, const Sales_data &); } ``` ```c++ //Sales_data.cc #include "Sales_data.h" namespace cplusplus_primer { // } ``` 程序想要使用我们定义的库必须包含必要的头文件,这些头文件的类和函数是定义在命名空间中的。 ```c++ #include "Sales_data.h" int main() { using cplusplus_primer::Sales_data; Sales_data trans1, trans2; return 0; } ``` 通常情况下不会将 `#include` 放在命名空间内部。 ### 全局命名空间 全局作用域中定义的名字,即在所有的类、函数及命名空间之外定义的名字,也就是定义在全局命名空间中。全局命名空间以隐式的方式声明,并且在所有程序中都存在。全局作用域中定义的名字被隐式地添加到全局命名空间中。作用域运算符同样也可以表示全局作用域的成员,因为全局作用域是隐式的,所以它没有名字。表示为`::member_name` 。 ### 嵌套的命名空间 直接看例子。 ```c++ namespace cplusplus_primer { //第一个命名空间 namespace wang { //第二个命名空间 //... } namespace dong { //与第二个命名空间并列的命名空间 //... } } ``` ### 内联命名空间 C++11引入了内联命名空间,和普通的嵌套命名空间不同的是,内联命名空间中的名字可以被外层命名空间直接使用。 ### 未命名的命名空间 未命名的命名空间是指关键字 `namespace` 后直接紧跟花括号,省略命名空间的名字的写法。未命名的命名空间中定义的变量拥有静态静态生命周期:它们在第一次使用前创建,直到程序结束后销毁。一个未命名的命名空间可以在给定的文件内不连续,但是不能跨越多个文件。每个文件定义自己的未命名的命名空间,如果两个文件都含有未命名的命名空间,则这两个空间相互无关。 > 在标准C++引入命名空间之前,程序需要将名字声明成 static 以使其对于整个文件有效。在文件中进行静态声明的做法是从C继承而来。在C中,声明为 static 的全局实体在其所在的文件外不可见。 > > 现在在文件中进行静态声明的做法已经被C++标准取代了,现在的做法是使用未命名的命名空间。 ## 使用命名空间 ### 命名空间的别名 命名空间的别名可以让我们为冗长的命名空间名字设定一个短得多的别名。 ```c++ namespace primer = cplusepluse_primer; ``` ### using声明 语法格式 ```c++ using namespace_name::name; //example using std::cout; using std::vector; ``` 一条using声明语句一次只引入一个命名空间内的成员。using声明中引入的名字遵循常规作用域规则:从using声明点开始,直到包含该using声明的作用域的末尾,名字都是可见的。外部作用域中定义的同名实体被屏蔽。 ### using指示 语法格式 ```c++ using namespace namespace_name; //example using namespace std; ``` using指示同using声明一样,可以使我们能够使用命名空间的简写形式,简写名字从using指示点开始,直到出现using指示的作用域的末尾。但不同的是using声明可以选择性的部分可见,但using指示使得特定命名空间名的所有可见。 ```c++ namespace A { int i, j; } void function1() { using namespace A; std::cout<