Hello,这里是关于C++的入门,C++的命名冲突问题,如果你像我一样对命名空间满是疑惑,只知道
using namespace std
,那么可以看下这篇文章,我自己之前的一些疑惑以及一些形象的理解。
命名冲突问题与命名空间
🌻命名冲突问题
首先,我们先来看一段很简单的C语言程序。
c
#include <stdio.h>
#include <stdlib.h>
int rand = 0;
int main()
{
printf("%d", rand);
return 0;
}
我们运行程序,发现程序出现了报错。如下:
rand 重定义;以前定义的是函数
我们在cpusplus.com
网站上搜索rand()
函数,便可简单了解。
rand()是来产生随机数的一个函数,内部使用线性同余法实现。
当我们又在程序中定义一个全局变量rand时,显然,这个变量rand与函数rand产生了命名冲突。
关于命名冲突问题,既可能是我们自己定义的变量与库进行冲突,也有可能是在一个大型项目中我们彼此之间的冲突。
因此,为了解决C语言的这个问题,C++在此上进行改善。
于是C++为了解决这个问题,定义了命名空间
。
于是,我们可以用C++来改善我们刚刚的C语言程序。将我们的全局变量rand放进命名空间。(用命名空间将自己定义的变量"封"起来。)
这时,我们编译程序,程序没有出现报错。
当我们将我们定义的全局变量rand
放进自己定义的命名空间的时候,也就是将自己定义的全局变量"封装起来",在程序运行时,访问的rand即是库函数中的rand()函数
。
我们打印的是rand函数的地址,将%d改成%p函数就不会报错了。
而当我们想要访问自己定义的全局变量时,我们即"指定"即可,即使用域作用限定符号::
。
即改成printf("%d\n",my_space::rand);
即可访问变量rand(因为我们自定义的命名空间并没有打开)。
关于命名空间,我们自定义的命名空间中不仅仅可以放变量,也可以放函数、结构体等。
我们加入一个函数,进一步扩展我们的命名空间。如下:
这里需要注意的是,既然要访问my_space中的函数,那么就要用域作用限定符来指定。(因为my_space并没有全部打开,没有"暴露"出来,我们要告诉编译系统,我们使用的Add()来自哪里,让编译系统直接去找。)
若没有限定的话,那么就会出现报错。如下。
我们可以再加入结构体:
可能有的童学会想,如果在极端情况下,我们自己定义的命名空间内的变量的名字也出现了冲突怎么办?或是在一个很大的项目中,由于代码行数过多,不经意间将自己已经定义过的的变量又再次定义怎么办呢?
其实,对于命名空间,是可以进行嵌套
的。从而将一个很大的命名空间内在定义几个小的命名空间,使得逻辑更清晰。同样,在小的命名空间内还可以进行进一步的嵌套。
🌻命名空间实现声明与定义的分离
下面我们来讨论一下如何用命名空间实现声明与定义的分离。
同一个文件的相同名字的命名空间一般会合并在一起。
我们用简单的栈来看。(其中压栈那个函数简单写得不严谨。)
这样将头文件和cpp文件都分别封装,不会发生命名冲突的问题。
同一个文件多个位置的同名的命名空间,编译器会把它们合并为一个。
🌻从默认指定---->展开访问---->指定展开
即展开命名空间
展开命名空间与展开头文件的区别?
展开头文件是在预处理阶段,编译系统将头文件中的内容拷贝过来。
而展开头文件,即是打开命名空间,(打开了封住它的一堵墙),将它"暴露"出来。
而仅仅展开头文件,头文件中的内容则不一定暴露出来。
比如关于C++标准库,
我们不进行展开,就会出现报错。
展开头文件仅仅是将头文件中的内容拷贝过来,但是它被C++的标准库给封装在一起,我们如果展开这个标注库std(也是一个命名空间
),我们就可以自由地使用了。
但是,关于命名空间的展开,我们也要分情况。
若是我们平时的小练习,那么我们自己定义的变量和库中重命名的概率很小很小,为了方便和简洁,就可以直接展开。
但若是在一个项目中,定义变量和函数过多既有可能与库的重冲突,又有可能与其他同事的冲突,所以,不建议展开。
比如,我们写简单的输出:
我们打开标准库:
cpp
#include <iostream>
using namespace std;
int main()
{
cout << "hello" << endl;
return 0;
}
也可以不打开标准库:(使用作用域限定符,指定编译系统到std命名空间去找cout。)
cpp
#include <iostream>
int main()
{
std::cout << "hello" << std::endl;
return 0;
}
像上面,我们每次指定展开命名空间很不方便;直接展开,全部暴露,又有冲突风险,那么我们用指定展开解决问题。
如下:
cpp
#include <iostream>
using std::cout;
using std::endl;
int main()
{
cout << "hello" << endl;
return 0;
}