回答这个问题之前,我们先看一下这样一段C语言代码
#include
int rand = 1;
int main()
{
printf("%d\n", rand);
return 0;
}
没有学过C语言的同学,可以把这里的printf("%d\n", rand)
,看成是c++的cout<
是printf()
的头文件。
毫无疑问,输出结果一定是1;
那如果再加一个头文件呢?
#include
#include
int rand = 1;
int main()
{
printf("%d\n", rand);
return 0;
}
此时再运行,就会看到如下报错:
error C2365: “rand”: 重定义;以前的定义是“函数”
为什么rand重定义了?
内有一个C语言自己的库函数
所以这里就同时存在了int rand;
和int rand(void)
两个同名变量,从而报错。
像这里,跟库里的变量名冲突还好,报错了,我们大不了换个变量名,但公司里一个项目几十人、几百人,很难避免。
C++之所以建立,可以说就是为了解决一些C语言的不足,那堆大佬为了解决命名冲突的问题,就提出了命名空间的概念。
要区分不同的域,我们就要为每个域都定义自己的名字,nemespace这个关键字就是这个作用。
namespace N1
{
//支持变量
int a = 1;
//支持函数
int f()
{
return 1;
}
//支持结构体/类
struct S
{
int _s;
}
}
像这样,namespace
,后面跟着命名空间的名字,然后接一对{}即可,{}中放命名空间的成员。
命名空间是支持嵌套的。
namespace N2
{
int a;
int f();
namespace N3
{
int b;
}
}
同一个工程中,允许存在多个相同名称的命名空间,编译器最后会把他们合成一个命名空间。
namespace N4
{
int a;
}
namespace N4
{
int b;
}
编译器处理之后就会变成这样:
namespace N4
{
int a;
int b;
}
所以说,这里的两个N4中当然也就不能有同名的变量了。
融合使命名空间可合并,嵌套又可避免合并之后产生内部冲突,这时把嵌套和融合两条规则加在,一起就可以实现如下操作:
一个公司,所有人都使用公司名、项目模块、个人名,的嵌套式空间命名方式,在合并之后可以避免命名冲突。
空间定义好了,那怎么使用呢?
#include
namespace N
{
int a = 10;
int b = 20;
}
int main()
{
printf("%d\n", a); // 该语句编译出错,无法识别a
return 0;
}
直接访问a肯定是不可以的,必须要有一种突破命名空间域的方式。
一般,根据不同情况,有三种方式可以使用。
使用using namespace
命名空间名称
引入
就像我们平时我们用的那句using namespace std;
这里的std其实就是个命名空间标示符
,C++标准库中的函数或者对象都是在命名空间std中定义的。
这里用了这句using namespace std;
就相当于直接把它的命名空间的壳拆了,也就是可以直接访问里边的所有函数和对象,如cout、cin、endl……
#include
namespace N
{
int a = 10;
int b = 20;
}
using namespace N;
int main()
{
printf("%d\n", a); // 正常打印
return 0;
}
这里使用了using namespace N;
将于域中的变量都释放于全局区,也就相当于俩全局变量(注:释放前也是全局变量,只不过受命名空间域的限制)
这种方式虽然最为方便,但危险性也是最高的,不管会不会用到,都会放出来,发生命名冲突的的可能性也更高。
使用using将命名空间中成员引入
有时我们写using namespace std;
也只为了使用cin
、cout
和endl
,所以我们不妨只将cin
、cout
和endl
放出来,语法如下:
using std::cin;
using std::cout;
using std::endl;
方式1中的案例,同样也可以用此方法:
using N::b;
int main()
{
printf("%d\n", b);
return 0;
}
在使用方式3之前,我们要先看一下域作用限定符的概念:
其实在c语言阶段其实就已经有这个符号了,而且也是用来解决变量名冲突
问题的
#include
int a = 0;
int main()
{
int a = 1;
printf("%d\n",a);
return 0;
}
这段代码会报错吗?
答案是不会,这里的两个a一个是全局变量,一个是局部变量,并不会发生访问冲突,再不做任何操作的条件下,会默认访问局部变量。
如果想访问全局域的那个a,只需要在前面加一个域作用限定符::
(俩冒号)
#include
using namespace std;
int a = 0;
int main()
{
int a = 1;
printf("访问局部变量(a):%d\n",a);
printf("访问全局变量(::a):%d\n",::a);
return 0;
}
这段代码的运行运行结果就是:
访问局部变量(a):1
访问全局变量(::a):0
还是上面的代码,如果a前面啥也没有,默认访问局部变量;
前面加上::,访问全局变量;
那么在::前面再加一个命名空间名呢?
顺理成章的,第三种访问方式产生了
在
变量名
前加命名空间名称
及::
#include
using namespace std;
int main()
{
cout << 1 << endl;
}
就可改成:
#include
int main()
{
std::cout << 1<< std::endl;
}
案例2:
#include
namespace N
{
int a = 10;
int b = 20;
}
int main()
{
printf("%d\n", N::a); // 正常打印
return 0;
}