为什么要使用命名空间?
- 一个大型的工程往往是由若干个人独立完成的,不同的人分别完成不同的部分,最后再组合成一个完整的程序。由于各个头文件是由不同的人设计的,有可能在不同的头文件中用了相同的名字来命名所定义的类或函数,这样在程序中就会出现名字冲突。
- 开发者定义的名字有可能会与C++库中名字产生冲突。
- 注:名字冲突就是在同一个作用域中有两个或多个同名的实体。
为了解决命名冲突 ,C++中引入了命名空间,所谓命名空间就是一个可以由用户自己定义的作用域,在不同的作用域中可以定义相同名字的变量,互不干扰,系统能够区分它们。
什么是命名空间?
命名空间又称为名字空间,是程序员命名的内存区域,程序员根据需要指定一些有名字的空间域,把一些全局实体分别存放到各个命名空间中,从而与其他全局实体分隔开。通俗的说,每个名字空间都是一个名字空间域,存放在名字空间域中的全局实体只在本空间域内有效。名字空间对全局实体加以域的限制,从而合理的解决命名冲突。
命名空间的格式
namespace 命名空间的名称
{
命名空间包含的类型(实体)
- 变量
- 常量
- 函数(定义或声明)
- 结构体
- 类
- 模板
- 命名空间
} //end of namespace
命名空间的使用方式
using编译指令
#include <iostream>
// std代表标准命名空间
// 如果一个名称空间中有多个实体,使用using编译指令,就会把该空间中的所有实体一次性引入到程序之中
using namespace std;
int main()
{
cout << "hello world" << endl;
return 0;
}
作用域限定符::
#include <iostream>
namespace xk
{
int number = 10;
void display()
{
//cout, endl 均是命名空间std的实体
std::cout << "xk::display()" << std::endl;
}
} //end of namespace xk
int main()
{
//通过 命名空间::实体 来使用命名空间
std::cout << "xk::number = " << xk::number << std::endl;
xk::display();
return 0;
}
using声明机制
#include <iostream>
//通过using的声明,可以在下面直接使用声明的cout与endl两个实体
using std::cout;
using std::endl;
int main()
{
cout << "hello world" << endl;
return 0;
}
三种命名空间使用的比较分析
- using编译指令
对于初学者对于命名空间中的实体并不熟悉,直接使用这种方式,可能会出现名字冲突
- 作用域限定符
每次使用命名空间中的实体都要加上 :: ,比较冗余
- using声明机制
初学者推荐使用,需要使用哪个实体就引入到程序中,不需要的实体就不引入,尽可能的减少犯错误的概率
匿名命名空间
不定义名字的命名空间称为匿名命名空间。
由于没有名字,该空间中的实体,其它文件无法引用,它只能在本文件的作用域内有效,它的作用域是从匿名命名空间声明开始到本文件结束。
在匿名空间中创建的全局变量,具有全局生存期,却只能被本空间内的函数等访问,是static变量的有效替代手段。
命名空间的嵌套及覆盖
#include <iostream>
using std::cout;
using std::endl;
int number = 1;
namespace xk
{
int number = 10;
namespace rl
{
int number = 100;
void display()
{
cout << "xk::rl::display()" << endl;
}
} // end of rl
void display(int number)
{
cout << "形参number = " << number << endl;
cout << "xk命名空间中的number = " << xk::number << endl;
cout << "rl命名空间中的number = " << xk::rl::number << endl;
cout << "全局变量number = " << ::number << endl;
}
} //end of xk
int main()
{
xk::rl::display();
xk::display(1000);
return 0;
}
命名空间的总结
- 提倡在已命名的名称空间中定义变量,而不是直接定义外部全局变量或者静态全局变量
- 如果开发了一个函数库或者类库,提倡将其放在一个名称空间中
- 对于using 声明,首先将其作用域设置为局部而不是全局
- 不要在头文件中使用using编译指令,这样,使得可用名称变得模糊,容易出现二义性
- 包含头文件的顺序可能会影响程序的行为,如果非要使用using编译指令,建议放在所有#include预编译指令后。