前言
我们都知道在C语言中存在着命名冲突的问题(即,在一个域中不能定义同名的变量、函数等,以免造成歧义),那么C 中是否解决了这个问题?相应的它又是如何解决的呢?这就涉及了我们今天有了解的知识——命名空间(关键词:namespace)。
一、命名空间
定义命名空间 ,需要使用namespace关键字,后面跟命名空间的名字,然后接一对{}
即可,{}
中即为命名空间的成员。
namespace Jinger //名称是自定义的,此处的名称是我的英文名
{
int a = 10;
//……
}
目的 :对标识符的名称进行本地化,以避免命名冲突或名字污染 作用 :定义一个域出来(相当于建立了一个围墙)将这个域中的变量、函数等与外面的域的空间隔离了,但是命名空间中的函数、变量本质上还是属于外面的域的。 作用原理 :影响编译器的查找规则,而不影响内容的生命周期和存储位置。
注意 : (1)在命名空间中的变量也是全局变量(只有定义在函数中的临时变量是局部变量,这种变量是在栈上创建的) (2)命名空间不改变变量的生命周期,只是限定了域(影响编译器的查找规则)
编译器的查找规则 : 正常情况下是先在局部查找,找不到再去全局中查找( 注意 :不会去命名空间中查找) 如果有命名空间,并且使用域作用限定符进行指定,会直接去命名空间中进行查找(不去全局或者局部进行查找)
二、命名空间的使用
1.命名空间可以定义变量、函数、结构体等
代码语言:javascript复制namespace Jinger
{
// 命名空间中可以定义变量/函数/类型
int a = 10;
int Add(int left, int right)
{
return left right;
}
struct Node
{
struct Node* next;
int val;
};
}
//注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
2.命名空间可以嵌套
即,一个命名空间中嵌套另一个命名空间。(不同级别的两个命名空间不要同名)
代码语言:javascript复制namespace Jinger1
{
int a = 1;
int b = 2;
int Add(int left, int right)
{
return left right;
}
namespace Jinger2
{
int c = 3;
int d = 4;
int Sub(int left, int right)
{
return left - right;
}
}
}
3.std
想必大家也很好奇,我在初识C 这篇文章的结尾所编写的第一个C 程序中的std
是什么意思。
std
是C 官方内容的命名空间(其中不包含C语言的内容,因为C 是继承了C语言的内容,所以在编写程序中可以直接使用C语言的内容)
注意 :在同一个工程中允许存在多个相同名称的命名空间(但是,这些命名空间必须是同级的),最后对整个工程内容进行编译时会将所有同名的命名空间中的内容进行合并。
4.命名空间的使用
命名空间内的成员该如何使用?
由于命名空间影响了编译器的查找规则,因此编译器不会自主的去查找命名空间的成员,需要使用符号::
,::
是域作用限制符(如果该符号左边是空白,就默认是全局域)
有三种方法使用命名空间中的成员:
(1)使用作用域限定符
加命名空间名称及作用域限定符
代码语言:javascript复制int main()
{
printf("%dn", Jinger::a);
return 0;
}
由于频繁使用Jinger::
会比较麻烦,为了方便,推荐用以下两种展开方式对命名空间中的内容进行展开(解除围墙的隔离),进而直接使用Jinger
中的内容。
(2)全部展开
使用using namespace后面跟命名空间名称
代码语言:javascript复制using namespce Jinger;
int main()
{
int b = 10;
printf("%dn", a);
printf("%dn", b);
Add(a, b);
return 0;
}
全部展开 :使用using namespsce std;
(这是初识C 的例子中展开官方内容的命名空间的方式,当然对于自己定义的命名空间也是用这种方式全部展开)。但是全部展开命名空间会带来不好的影响:当围墙被全部拆除,命名冲突的问题就会再次出现。因此全部展开这种方式,多用于小程序、小项目中,大的工程项目不能使用。
(3)指定展开
使用using将命名空间中某个成员引入
代码语言:javascript复制using Jinger::a;
int main()
{
printf("%dn", a);
printf("%dn", Jinger1:: a);
return 0;
}
指定展开 :使用using std::cout;
意思是指定展开std
命名空间中的cout
,在该源文件中,如果使用cout
,就不需要在前面加std::
了。
总结
为了能解决命名冲突问题,同时又能方便编写代码,使用指定展开会比较好(即,将这个程序中我们会经常性使用的函数等进行展开,其他内容不展开),这样只需要在自定义某些内容的时候避免与指定展开的内容名称起冲突即可。
总结
以上就是今天要讲的内容,本文介绍了C 中命名空间的相关概念。本文作者目前也是正在学习C 相关的知识,如果文章中的内容有错误或者不严谨的部分,欢迎大家在评论区指出,也欢迎大家在评论区提问、交流。 最后,如果本篇文章对你有所启发的话,希望可以多多支持作者,谢谢大家!