命名空间
命名空间或者叫名字空间(名字就是namespace)是为了在大型项目中防止标识符冲突才引入的,实际上就是可以由用户命名的作用域。
touzani的专栏的这篇C++ 命名空间namespace,我觉得写的很明白(不敢说好坏,因为我也是抱着学习的态度读技术博客),该部分大量参考了这篇博文。
与命名空间相关的概念:
声明域(declaration region)—— 声明标识符的区域。如在函数外面声明的全局变量,它的声明域为声明所在的文件。在函数内声明的局部变量,它的声明域为声明所在的代码块(例如整个函数体或整个复合语句)。
潜在作用域(potential scope)—— 从声明点开始,到声明域的末尾的区域。因为C++采用的是先声明后使用的原则,所以在声明点之前的声明域中,标识符是不能用的。即,标识符的潜在作用域,一般会小于其声明域。
作用域(scope)—— 标识符对程序可见的范围。标识符在其潜在作用域内,并非在任何地方都是可见的。例如,局部变量可以屏蔽全局变量、嵌套层次中的内层变量可以屏蔽外层变量,从而被屏蔽的全局或外层变量在其倍屏蔽的区域内是不可见的。所以,一个标识符的作用域可能小于其潜在作用域。C语言中文网的解释更干脆:”我们把变量在程序中可以使用的有效范围称为变量的作用域。”
原来C++标识符的作用域:全局作用域、块作用域、类作作用域。如果要按范围大小排个序的话,我的理解是这样:
块作用域 < 类作用域 < 全局作用域
而命名空间介于类作用域与全局作用域之间。
命名空间可以是全局的,也可以位于另一个命名空间之中,但是不能位于类和代码块中。所以,在命名空间中声明的名称(标识符),默认具有外部链接特性(除非它引用了常量),也就是具有全局作用域,但并不是全局可见的。
在所有命名空间之外,还存在一个全局命名空间,它对应于文件级的声明域。因此,在命名空间机制中,原来的全局变量,现在被认为位于全局命名空间中。
定义命名空间:
有名的命名空间:
namespace 命名空间名 {
声明序列可选
}
无名的命名空间:
namespace {
声明序列可选
}
可以在命名空间的定义内,定义命名空间的成员(内部定义)。也可以只在命名空间的定义内声明成员,而在命名空间的定义之外,定义命名空间的成员(外部定义)。
例如:
namespace Outer // 命名空间Outer的定义
{
int i; // 命名空间Outer的成员i的内部定义
namespace Inner // 子命名空间Inner的内部定义
{
void f() // 命名空间Inner的成员f()的内部定义,其中的i为Outer::i
{
i++;
}
int i;
void g() // 命名空间Inner的成员g()的内部定义,其中的i为Inner::i
{
i++;
}
void h(); // 命名空间Inner的成员h()的声明
}
void f(); // 命名空间Outer的成员f()的声明
// namespace Inner2; // 错误,不能声明子命名空间
}
void Outer::f() // 命名空间Outer的成员f()的外部定义
{
i--;
}
void Outer::Inner::h() // 命名空间Inner的成员h()的外部定义
{
i--;
}
// namespace Outer::Inner2 // 错误,不能在外部定义子命名空间
// {
// /*……*/
// }
注意:
不能在命名空间的定义中声明(另一个嵌套的)子命名空间,只能在命名空间的定义中定义子命名空间。
也不能直接使用“命名空间名::成员名 ……”定义方式,为命名空间添加新成员,而必须先在命名空间的定义中添加新成员的声明。
另外,命名空间是开放的,即可以随时把新的成员名称加入到已有的命名空间之中去。方法是,多次声明和定义同一命名空间,每次添加自己的新成员和名称。例如:
namespace A
{
int i;
void f();
} // 现在A有成员i和f()
namespace A
{
int j;
void g();
} // 现在A有成员 i、f()、j和g()
使用命名空间:
- 使用作用域限定符:
::
; - 使用using声明机制:
using 名称空间::实体名
- 使用using编译指令:
using namespace 名称空间名;
至于using声明语句或编译指令将该实体的可见域扩展到什么程度,这取决于using语句的书写位置,换言之,这取决于using语句的可见域:
#include <iostream>
#include <string>
using std::string; // using声明在全局区域,string全局可见(不考虑局部同名覆盖时)
void Display(const string text)
{
// using namespace std; // 也可以,std中的所有实体仅在该块作用域内可见
using std::cout; // using声明在局部区域,string仅该块作用域内可见
using std::endl;
cout << text<< endl;
}
int main()
{
string str = "code the world!";
Display(str);
// cout << str << endl; // 有效但不可见,可以通过std::cout、std::endl来使用
return 0;
}