命名空间
- 1.命名空间使用的背景
- 1.背景
- 2.命名空间的定义(namespace)
- 2.1正常的定义
- 2.2 命名空间可以嵌套定义
- 2.3允许命名空间相同
- 3.域作用限定符(::)和命名空间的使用
- 3.1域作用限定符(::)
- 3.2 命名空间的使用
- 3.2.1 加命名空间名词和域作用限定符
- 3.2.2 使用using将命名空间中某个成员引入
- 3.3 使用using namespace 命名空间名称 引入
- 4.理解using namespace std以及为什么尽量使用局部展开
- 5.总结
1.命名空间使用的背景
1.背景
我们先来看以下这段代码
#include <stdio.h>
#include <string.h>
int strlen = 10;
int main()
{
printf("%d", strlen);
return 0;
}
这段代码会报以下错误:
“strlen”: 重定义;以前的定义是“函数”
意思就是说,我们定义的变量名strlen与string.h库的strlen函数名冲突了,因为同一个作用域里面不能有相同的名称,但是C语言没办法解决这种问题,所以C++中引入了命名空间这个概念。
其实还有一个原因就是当一个项目需要多个人写的时候,就难免会出现名称相同的情况,这时候如果是C语言我们对于这种问题只能要求程序员之间去修改名称,但是如果是C++的话,我们可以用命名空间,来允许多个名称相同的情况。
2.命名空间的定义(namespace)
定义命名空间,需要用到namespace关键字,然后加上一个命名空间的名字,最后花括号{}括起来即可
2.1正常的定义
namespace A //A的命名空间
{
int a = 20;
int b = 30;
...//也可以定义函数
}
namespace B //B的命名空间
{
int a = 40;
int b = 60;
}
2.2 命名空间可以嵌套定义
namespace N1
{
int a;
int b;
int Add(int left, int right)
{
return left + right;
}
namespace N2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
2.3允许命名空间相同
当多个命名空间相同时,实际上会合成一个命名空间。
3.域作用限定符(::)和命名空间的使用
3.1域作用限定符(::)
域作用限定符 ::
使用方式就是 作用域 ::变量名,如果作用域为空格则为在全局域中寻找变量。
//我们知道,当一个变量有在全局域中存在,也在局部中存在,会优先使用局部的变量。
//这时候如果我们就想用全局变量就要加上域作用限定符::
//如下:前面为空格表示全局变量。
int i = 20;//全局变量
int main()
{
int i = 10;
printf("%d", i);//局部变量,10
printf("%d", ::i);//20
return 0;
}
3.2 命名空间的使用
我们以下用命名空间的代码放在我们自己的test.h头文件中
namespace A //A的命名空间
{
int a = 20;
int b = 30;
}
namespace B //B的命名空间
{
int a = 40;
int b = 60;
}
3.2.1 加命名空间名词和域作用限定符
命名空间名称 + :: + 变量
#include "test.h"
int main()
{
printf("%d", A::a); //20
printf("%d", B::a);// 40
return 0;
}
3.2.2 使用using将命名空间中某个成员引入
这种方式也叫局部展开,就是把命名空间中的一些变量在全局域中展开了。
#include "test.h"
using A::a;
int main()
{
printf("%d", a); //20
printf("%d", B::a);// 40
return 0;
}
3.3 使用using namespace 命名空间名称 引入
这种方式也叫全局展开,就是把命名空间中的所有变量在全局域中展开。
#include "test.h"
using namespace A;
int main()
{
printf("%d", a); //20
printf("%d", b);//30
printf("%d", B::a);// 40
return 0;
}
4.理解using namespace std以及为什么尽量使用局部展开
由上面的知识我们可以知道,using namespace std,就是利用using 将 std 全局展开,而std就是我们的standard,就是C++标准库。
因为标准库非常的庞大,所以程序员在选择的类的名称或函数名时就很有可能和标准库中的某个名字相同。所以为了避免这种情况所造成的名字冲突,就把标准库中的一切都放在名字空间std中。但这又会带来了一个新问题。无数原有的C++代码都依赖于使用了多年的伪标准库中的功能,他们都是在全局空间下的。 所以就有了和<iostream.h>等等这样的头文件,一个是为了兼容以前的C++代码,一个是为了支持新的标准。 iostream和iostream.h,前者没有后缀。实际上,在你的编译器include文件夹里面可以看到,二者是两个文件。打开文件就会发现,里面的代码是不一样的。 后缀为.h的头文件c++标准已经明确提出不支持了,早些的实现将标准库功能定义在全局空间里,声明在带.h后缀的头文件里,c++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。 因 此,当使用<iostream.h>时,相当于在c中调用库函数,使用的是全局命名空间,也就是早期的c++实现;当使用< iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std;命名空间std封装的是标准程序库的名称。
这是一段C++代码
写法1:
#include <iostream>
using namespace std;//全局展开
int main()
{
cout << "hello world" << endl;
return 0;
}
写法2:
#include <iostream>
using std::cout;//局部展开
using std::endl;
int main()
{
cout << "hello world" << endl;
return 0;
}
写法3:
#include <iostream>
int main()
{
std::cout << "hello world" << std::endl;//指定命名空间
return 0;
}
在进行工程项目时,我们不建议将std全局展开,而是采用局部展开,或者指定命名空间访问。
之所以在进行工程项目时不建议将std全局展开,主要是为了防止命名冲突。
比如我正在使用两个库
using namespace A;
using namespace B;
不管是调用A里面的函数add(),还是B里面的函数sub(),都是可以的。
但是如果有一天,我的A库要升级的话,里边新加了一个函数叫sub,这样就出现问题了,因为它和命名空间B里的sub冲突了。那我是不是要一个一个去解决,费时费力。
如果我当初没有全局展开这些名称,而是A::add(),B::sub(),A::sub(),那就没有命名冲突的问题了。
所以不建议全局导入命名空间,而是要用哪个就显示哪个命名空间,这样代码本身的阅读性也好。
5.总结
命名空间namespace:定义方式namespace + {},正常定义,也可以嵌套定义(自然可以嵌套使用,如A::B::i),以及相同的名字的命名空间会合到一起。
using使用命名空间
域作用限定符::配合命名空间名称使用
三种使用命名空间方式:全局展开,局部展开,指定
最重要的是在进行工程项目时最好不要用全局展开,防止命名冲突,