命名空间(Namespace)表示标识符(identifier)的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。
例如,设Bill是X公司的员工,工号为123,而John是Y公司的员工,工号也是123。由于两人在不同的公司工作,可以使用相同的工号来标识而不会造成混乱,这里每个公司就表示一个独立的命名空间。如果两人在同一家公司工作,其工号就不能相同了,否则在支付工资时便会发生混乱。
这一特点是使用命名空间的主要理由。在大型的计算机程序或文档中,往往会出现数百或数千个标识符。命名空间(或类似的方法,见“命名空间的模拟”一节)提供一隐藏区域标识符的机制。通过将逻辑上相关的标识符组织成相应的命名空间,可使整个系统更加模块化。
在编程语言中,命名空间是一种特殊的作用域,它包含了处于该作用域内的标识符,且本身也用一个标识符来表示,这样便将一系列在逻辑上相关的标识符用一个标识符组织了起来。许多现代编程语言都支持命名空间。在一些编程语言(例如C++和Python)中,命名空间本身的标识符也属于一个外层的命名空间,也即命名空间可以嵌套,构成一个命名空间树,树根则是无名的全局名空间。
函数和类的作用域可被视作隐式命名空间,它们和可见性、可访问性和对象生命周期不可分割的联系在一起。
C++中的命名空间
在C++语言中,命名空间使用namespace来声明,并使用{ }来界定命名空间的作用域. 例:
namespace foo { int bar; }
命名空间可以是全局的,也可以位于另一命名空间之中;但不能在类和代码块之中。所以,在命名空间中声明的名称,默认具有外部链接特性(除非声明了常量,常量默认是静态于一个编译单元)。
在所有命名空间之外,还存在一个全局命名空间,对应于不使用命名空间时的全局作用域。例如,::new是全局new运算符。
按照是否有名字,可分为有名字的命名空间与无名命名空间。后者为:
namespace { namespace-body(即声明序列(可选)) }
无名命名空间的成员在本编译单元中可以不加显式引用(实际上也没法显示引用无名名字空间)而直接使用;但在其他编译单元中不可见。即具有内部链接属性。
命名空间的成员,是在命名空间体的花括号内声明了的名称。可以在命名空间体之外,给出命名空间成员的定义。即命名空间的成员声明与定义可以分开。
子命名空间必须定义在上层命名空间体之内。禁止把子命名空间的声明与定义分开。
不能以“命名空间名::成员名;”方式,在命名空间体之外为命名空间添加新成员.必须在命名空间体之中添加新成员的声明。
可以多次声明和定义同一命名空间,每次给这一命名空间添加新成员。编译器自动合并这些同名的命名空间。(实际上编译器并不合并一个命名空间、也不枚举一个命名空间有哪些成员。编译器仅仅是给所有命名空间的成员加上名字限定符qualifier作为其装饰名字mangling name)
可以在一个命名空间中引入其他命名空间的成员。例如:
namespace myNameSpace{ using namespace His_NameSpace; using OLib::List; void my_func(String &, List &); }
引用命名空间的成员,有下述办法:
- 使用命名空间的作用域解析运算符::,如:std::cout
- using namespace 命名空间名[::命名空间名…];该语句使指定的命名空间中的所有成员都可直接使用。如果引入的名称与局部名称发生冲突,则编译器并不会发出任何警告信息,而只是用局部名称自动覆盖命名空间中的同名成员。
- using 命名空间名::[命名空间名::……]成员名; 引入命名空间中的一个成员。如果引入的名称与局部名称发生同名冲突,编译器会报错。
命名空间可以有别名:namespace 别名 = 命名空间名; 这使得名字较长的命名空间可以方便地用较短的别名来引用。
原文链接:命名空间