相信大家在cpp代码中经常可以看到头文件下面看到using namespace std这样一个语句,每次写c++代码时都要加上这句话,否则就会报错,不知道这句话酒精有什么作用,是什么意思;其实这是c++提供的命名空间;
所谓的命名空间就是一个域,可以由我们自己创造,我们可以在其中定义各种变量、函数、结构体、类等等;
由于C++大量存在的标识符(变量、函数和类的名称),并且这些标识符处于全局作用域中,为避免命名冲突或命名污染,namespace
对这些标识符的名称进行了本地化,使编译器在全局作用域中不直接检索到这些标识符。
下面我们来看一段代码:
#include<stdio.h>
int rand = 20;
int main()
{
printf("%d", rand);
return 0;
}
这段代码其实是可以成功运行的,但即使能够运行,也是有着严重的缺陷,我在全局域中定义了一个变量rand,rand是什么?我们通常用来产生随机数的一个函数,rand是一个函数的名字,因此命名上发生了冲突; 我们试想一个公司员工在进行一个项目的时候,代码量可想而知是十分巨大的,在这其中存在着各种各样的命名,不免有些命名“撞”到一块去,引发冲突,就很难受了,而命名空间就是解决这样的问题而出现;
定义命名空间需要使用关键字namespace,顾名思义,就是命名空间的意思;我们依旧一上面的代码为例,倘若我将rand放在命名空间里面然后进行访问是不是就不会发生冲突了; 代码如下:
#include<stdio.h>
namespace bit {
int rand = 20;
int add(int a,int b)
{
return a+b;//函数、结构体也是可以的
}
}
int main()
{
printf("%d", bit::rand);
return 0;
}
需要注意的是1.访问命名空间内容时,需要指明是哪个命名空间,因为命名空间不只可以定义一个,以bit::rand这样的形式进行访问其中的元素、函数等等; 2.命名空间里面的变量没有生命周期,也就是空间里的变量是全局变量,在main函数中是可以改变空间中变量的值的。
我们在前面c中学过在main函数中的访问元素时,遵循局部优先,比如我定义了一个全局变量a并初始化为10,但是我在main函数中有进行了重新赋值为20,那么我打印的a的值就是20;局部要优于全局. 那么再加上命名空间这种域呢? 在c++中,我们访问元素的顺序仍然是局部大于全局,即使是有了命名空间,也不会主动访问该空间
#include<stdio.h>
namespace bit {
int rand = 20;
}
int main()
{
printf("%d", rand);
return 0;
}
就像这样我要访问rand这个变量,编译器会先在局部域中寻找,找不到了就去全局域找,如果在全局域中也找不到就会报错,系统是不会主动在命名空间中访问的,因此我们手动进行访问有时是必要的。
举个例子,我们在bit1的命名空间中定义了一个普通变量a,在bit2命名空间中定义了一个普通变量b,然后进行访问,这时候只要指明指那个命名空间就不会发生冲突。代码如下:
#include<stdio.h>
namespace bit1
{
int a=10;
}
namespace bit2
{
int a = 20;
}
int main()
{
printf("%d\n", bit1::a);
printf("%d\n", bit2::a);
return 0;
}
命名空间中的元素具有全局变量的性质,但不能将其完全看成全局变量,在不同的域中命名是可以形同的,并不会发生冲突。
倘若我定义了多个命名空间,在这些明明空间中有几个变量的命名是相同,那他们会发生冲突吗? 会的。当我们定义了多个相同的名字的命名空间的话,那么这些命名空间编译时就会发生合并,合并成一个共同的域,在同一个域中是不能出现命名相同的元素名称的。但命名空间支持嵌套。
我们未解决上述的问题,可以更改一个空间的名字之外,就是可以使用嵌套,代码如下:
#include<stdio.h>
namespace bit {
namespace bit1
{
int a = 10;
}
}
namespace bit1
{
int a = 20;
}
int main()
{
printf("%d\n", bit::bit1::a);
printf("%d\n", bit1::a);
return 0;
}
我们可以将其一个空间进行嵌套,这样两个空间就不冲突啦,然后访问时需要进行二次::访问;
命名空间的展开等同与展开头文件(将其内容进行拷贝),而是类似与函数的声明。举个例子,代码如下:
#include<stdio.h>
namespace bit {
int rand = 20;
int add(int a, int b)
{
return a + b;
}
}
int main()
{
printf("%d", bit::rand);
printf("%d", bit::rand);
printf("%d", bit::rand);
printf("%d", bit::rand);
printf("%d", bit::rand);
printf("%d", bit::rand);
printf("%d", bit::rand);
return 0;
}
当我们需要多次访问空间中的元素时,我们每一次都需要进行bit::这样的访问的方式是很繁琐的,所以c++支持的命名空间的展开,就很好的解决了这类问题(在一个文件中),上代码:
#include<stdio.h>
namespace bit {
int rand = 20;
int add(int a, int b)
{
return a + b;
}
}
using namespace bit;
int main()
{
printf("%d", rand);
return 0;
}
展开命名空间的格式是using namesapce +名称,在定义好的命名空间的下面进行展开,这样下面的访问的空间中的元素就可以直接访问;但为什么说是在一个文件中好用的?因为我们平时写代码都是只使用一个文件就足够了,在一个文件中我们通常只会定义一个命名空间,所以不会与其他命名空间发生冲突;
试想如果我在一个文件中展开了,2个命名空间,一个空间存在该元素另一个不存在还好;但是我要访问的元素在两个空间中都存在,那到底访问的是哪一个呢?这就会发生冲突了。所以在使用时也需要注意使用的情况;
有时候我们并不需要将整个命名空间全部展开,所以我们可以只对其中的指定的元素进行展开; 代码如下:
#include<stdio.h>
namespace bit {
int rand = 20;
int add(int a, int b)
{
return a + b;//函数、结构体也是可以的
}
}
using bit::rand;
int main()
{
printf("%d", rand);
printf("%d", bit::add(2, 5));
return 0;
}
通过using bit ::rand我们可以对rand进行展开,访问时可以直接访问,但是其他没有指定展开的依旧要使用原来的方式进行访问,当然指定访问的个数并不是唯一的,可以多写几个using bit ::元素,来根据情况使用;
using namespace std;涉及到C++输入、输出流;请看下篇博客;