命名空间的作用
命名空间是为了防止名字冲突提供更加可控的机制。命名空间分割了全局命名空间,其中每一个命名空间是一个作用域。
命名空间的定义
命名空间由三部分组成,分别是namespace、空间名字和一系列由花括号括起来的声明和定义。只要能出现在全局作用域中的声明都能置于命名空间中,例如:类、变量(及其初始化操作)、函数(及其定义)、模板和其他命名空间等。
命名空间的定义既可以定义在全局变量的作用域内,也可以定义在其他的命名空间中,但是不能定义在函数或者类的内部。
命名空间的定义可以是不连续的,定义在该命名空间的名字可以被其他命名空间中的其他成员直接访问,也可以被这些成员内嵌作用域中的任何单位访问。命名空间可以不连续的特性使我们可以将几个独立的接口和实现文件组成一个命名空间:
- 命名空间的一部分成员的作用是定义类,以及声明作为类接口的函数及对象,则这些成员应该置于头文件中,这些头文件将被包含在使用了这些成员的文件中
- 命名空间成员的定义部分则置于另外的源文件中
并且命名空间的外部来定义该命名空间的成员,例如:
cplusplus_primer::Sales_data
cplusplus_primer::operator+(const Sales_data& lhs
const Sales_data& rhs)
{
Sales_data ret(lhs);
}
需要注意的是一般不把#include放到命名空间的内部。这样做了这就意味着把头文件中的所有的名字定义成该命名空间的成员。
全局命名空间
全局作用域定义的名字就是定义在全局命名空间中,全局命名空间以隐式的方式声明,并且任何程序中多存在全局命名空间。由于全局命名空间是隐式的,所以并没有名字,通常是通过以下的方式来实现访问的:
::number_name
嵌套的命名空间
内层命名空间声明的名字将会隐藏外层命名空间声明的同名成员,在嵌套的内层命名空间中定义的名字只有在内层命名空间中有效,外层命名空间要想访问它必须添加命名空间的前缀符进行限定。
内联命名空间
与普通的命名空间不同,内联命名空间的名字可以直接被外层的命名空间直接使用,无需添加该内联命名空间的名字作为前缀进行限定。当应用程序的代码在一次发布和另一次发布之间进行了改变时,通常使用这个机制。使用方式如下:
头文件FifthEd.h
inline namespace FifthEd
{}
namespace FifthEd//inline 关键字必须出现在命名空间第一次定义的地方,但是后续打开该命名空间时可以不写该关键字
{
class Query_base{};
}
头文件FourthEd.h
namespace FourthEd
{
class Item_base{};
}
于是在cplusplus的命名空间中可以如下进行定义
namespace cplusplus_primer{
#include "FourthEd.h"
#include "FifthEd.h"
}
按照上述的使用方式,如果想获得FifthEd中的类,可以使用cplusplus_primer::进行限定;如果想获得FourthEd中的类,可以使用cplusplus_primer::FourthEd::进行限定。
未命名的命名空间
未命名的命名空间指的是namespace后面紧跟这花括号。未命名的命名空间中定义的成员拥有静态声明周期,在程序第一次创建之前使用,并且直到程序结束时才会销毁。
之所以提出未命名的命名空间的原因是:在早期时C++将变量声明成static以使其对于整个文件都有效,但是后来在文件中进行静态声明的方式已经被C++标准取消了,现在的方式使用未命名的命名空间来取代static。
注意
- 一个未命名的命名空间可以在某一个给定的文件中不连续,但是,不可以跨越多个文件。
- 每一个文件定义自己的未明名的名字空间,如果两个文件都有未命名的名字空间,则这两个命名空间没有关系。
- 不同的两个文件中的未命名的命名空间中可以定义相同的名字,并且这些名字属于不同的实体。
- 如果一个头文件定义了一个未命名的命名空间,则包含该头文件的文件中对应不同的实体。
- 未命名的命名空间的名字的作用域与该命名空间所在的作用域相同。
未命名的命名空间也可以嵌套,例如:
namespace local {
namespace {
int i;
}
}
local::i = 42; // 正确
使用命名空间成员
命名空间别名
别名的声明方式如下:
namespace cplusplus_primer
{
}
namespace primer = cplusplus_primer;
注意
- 必须是在命名空间定义之前就声明别名。
- 一个命名空间可以有好几个同义词或者别名,所有的别名都与命名空间原来的名字等价。
using声明
一个 using 声明一次只引入一个命名空间成员。using 声明的作用域从 using 声明点开始,直到包含 using 声明的作用域的末尾,名字都是可见的,外部作用域中定义的同名实体被屏蔽。在有效作用域结束之后,就必须使用完整的经过限定的名字。using 声明可以出现在全局、局部、类的作用域 和 名字空间中。在类作用域中using声明只能引用基类成员。
using指示
一个 using 声明一次引入一个特定命名空间的所有成员。using 指示可以出现在全局、局部的作用域 和 名字空间中,不会出现在类的作用域中。与using声明不同的是,using声明的名字的作用域与using声明的语句的作用域一致;using指示将所声明的命名空间的所有成员提升到同时包含命名空间和using指示的最近作用域。
using声明、指示和头文件
如果头文件中在其顶层作用域中包含using指示或者using声明,则会将该命名空间中的名字包含到所有包含该名字的文件中。所以通常在函数或者命名空间中使用using指示或者using声明。
参考链接:
C++名字空间/C++命名空间
C++学习之命名空间