目录
- namespace命名空间
- 局部域和全局域
- namespace
- 展开命名空间
- 指定命名空间
- 命名空间的嵌套
- 不同文件中的同名命名空间
- using namespace std 是什么意思
我们先看一段C代码:
#include <stdio.h>
#include <stdlib.h>
int rand = 0;
int main()
{
printf("%d", rand);
return 0;
}
我们直接看可能不会发现问题,但是这段代码是运行不出来的
原因就是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;
}
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;
}
答案是会发生命名冲突
这是因为展开后就代表着里面的内容就暴露到全局,与原全局域中的a
冲突
所以可以看出,using namespace
不是特别好,using namespace
的本意是为了防止冲突,但是展开后又会发生冲突
所以不要轻易的使用using namespace
指定命名空间
我们还可以通过展开命名空间的方法去搜索命名空间域中的a
也是使用域作用限定符::
printf("%d\n", a);//输出局部域中的a
printf("%d\n", ::a);//输出全局域中的a
printf("%d\n", test::a);//输出命名空间域中的a
这样,就不会发生任何冲突
所以,如果只想使用某个命名空间中的一两个函数或变量,指定命名空间就可以,没有必要展开整个命名空间
命名空间的嵌套
命名空间是支持嵌套的,因为如果我们把所有的变量、函数、结构都放在一个命名空间中时,也会不可避免的发生冲突
//命名空间的嵌套
namespace A1
{
int aa = 10;
namespace A2
{
int aa = 20;
}
}
怎么去访问嵌套的命名空间中的元素呢?
多次使用::
printf("%d\n" ,A1::aa); //访问A1中的aa
printf("%d\n", A1::A2::aa);//访问被嵌套的A2中的aa
不同文件中的同名命名空间
在不同文件中的同名命名空间,最终会合并在一起
这里我们在2个不同的头文件中创建了同名命名空间
到了源文件中,这2个命名空间就自动合并了
#include "A.h"
#include "B.h"
int main()
{
std::cout << hhh::a << std::endl;
std::cout << hhh::b << std::endl;
}
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;
}
在每一个cout
和·endl
前面都要加上std::
,这么看起看来十分麻烦且枯燥,所以还有一种写法。就是将常用的展开
//将常用的展开
using std::cout;
using std::endl;
int main()
{
cout << "hello" << endl;
}
这样写,即避免了直接展开命名空间的风险,也减少了写std
的次数