我们先看一段C代码:
#include <stdio.h> #include <stdlib.h> int rand = 0; int main() { printf("%d", rand); return 0; } 1
我们直接看可能不会发现问题,但是这段代码是运行不出来的
原因就是rand名与stdlib.h库中的函数命冲突,所以运行不出来
命名冲突的发生有2个原因:
1.跟库中冲突
2.一个项目不同部分由不同人编写,最后合并时发生命名冲突
为了避免自己定义的变量名或函数命与库中的名冲突,于是在C++中引入了命名空间这一概念。
namespace命名空间
局部域和全局域
我们先了解一下 局部域 和 全局域,在同一域中不可以创建2个同名变量,但在同一域中可以创建2个同名变量
下面在局部域和全局域建立2个同名变量
#include <iostream> int a = 1;//全局域 int main() { int a = 0;//局部域 printf("%d\n", a); return 0; }
那么在这里如果要输出a的值,那么输出的是全局域中的值还是局部域中的值呢?
答案是:输出局部域中的a值
所以可以得出一个结论:搜索范围是先局部域再全局域,默认是在局部域中搜索,如果没有局部域,再在全局域中搜索
如果想要输出全局域中的a怎么办呢?
使用::域作用限定符,::a就表示全局域中的a
#include <iostream> int a = 1;//全局域 int main() { int a = 0;//局部域 printf("%d\n", ::a); return 0;
10
namespace
下面我们通过namespace创建一个命名空间域
namespace test { int a = 2; }
那么现在我们怎么输出这个命名空间域中的a呢?
C++中的搜索范围是:局部域->全局域,如果不展开命名空间或指定访问命名空间,是不会去命名空间中搜索的
只有展开命名空间或指定访问命名空间才会搜索到命名空间域中
可以看到,不展开命名空间也不指定访问命名空间,是不会输出命名空间域中的a
#include <iostream> namespace test { int a = 2; } //int a = 1;//全局域 int main() { //int a = 0;//局部域 printf("%d\n", ::a); return 0; }
展开命名空间
下面用using namespace test展开命名空间域
说明:这里展开的意思是编译器是否去域里进行搜索
与#include本质不同,不要错误理解
#include <iostream> namespace test { int a = 2; } using namespace test;//展开命名空间域 int a = 1;//全局域 int main() { int a = 0;//局部域 printf("%d\n", a); return 0; }
这时,三个域中的a是可以共存的,按照搜索顺序,这里会输出局部域中的a
这里如果删除掉全局域和局部域中的a,这里就会输出命名空间域中的a
如果去掉局部域中的a,展开命名空间域,此时在全局域和命名空间域中都有一个a,那么这时如果不使用::,会输出哪个a呢
#include <iostream> namespace test { int a = 2; } using namespace test;//展开命名空间域 int a = 1;//全局域 int main() { //int a = 0;//局部域 printf("%d\n", a); return 0; }
5
答案是会发生命名冲突
这是因为展开后就代表着里面的内容就暴露到全局,与原全局域中的a冲突
所以可以看出,using namespace不是特别好,using namespace的本意是为了防止冲突,但是展开后又会发生冲突
所以不要轻易的使用using namespace
指定命名空间
我们还可以通过展开命名空间的方法去搜索命名空间域中的a
也是使用域作用限定符::
printf("%d\n", a);//输出局部域中的a printf("%d\n", ::a);//输出全局域中的a printf("%d\n", test::a);//输出命名空间域中的a 1
这样,就不会发生任何冲突
所以,如果只想使用某个命名空间中的一两个函数或变量,指定命名空间就可以,没有必要展开整个命名空间
命名空间的嵌套
命名空间是支持嵌套的,因为如果我们把所有的变量、函数、结构都放在一个命名空间中时,也会不可避免的发生冲突
//命名空间的嵌套 namespace A1 { int aa = 10; namespace A2 { int aa = 20; } }
9
怎么去访问嵌套的命名空间中的元素呢?
多次使用::
printf("%d\n" ,A1::aa); //访问A1中的aa printf("%d\n", A1::A2::aa);//访问被嵌套的A2中的aa 1 2
不同文件中的同名命名空间
在不同文件中的同名命名空间,最终会合并在一起
这里我们在2个不同的头文件中创建了同名命名空间
到了源文件中,这2个命名空间就自动合并了
#include "A.h" #include "B.h" int main() { std::cout << hhh::a << std::endl; std::cout << hhh::b << std::endl; } 1
using namespace std 是什么意思
std是C++库的命名空间,std中包含了STL和C++库
C++中常用的输入输出也都在std中,所以我们平常在创建cpp文件后都会第一时间把using namespace std写上
#include <iostream> using namespace std; int main() { cout<<"hello"<<endl; }
的内容,我们知道 直接展开会有风险,如果自己定义跟库重名,就会报错
所以在平时日常练习时可以展开,在一些项目中建议指定访问,不轻易展开命名空间
下面是通过指定访问实现输出:
#include <iostream> int main() { std::cout<<"hello"<<std::endl; std::cout<<"hello"<<std::endl; std::cout<<"hello"<<std::endl; std::cout<<"hello"<<std::endl; } 1
在每一个cout和·endl前面都要加上std::,这么看起看来十分麻烦且枯燥,所以还有一种写法。就是将常用的展开
//将常用的展开 using std::cout; using std::endl; int main() { cout << "hello" << endl; }