C++的特性:命名空间
文章目录
在学习C++之前,我们需要先了解C++相对于C增加了一些什么特性,这些新增功能和特性一般都是为了解决C语言的的一些遗留问题或者不合理的地方。
场景引例(命名冲突):
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
int main()
{
printf("%d\n", rand);
return 0;
}
// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”
运行报错:
这是因为在stdlib库里rand被用作了rand()函数名,所以在预编译阶段头文件展开后,则与全局变量rand产生了冲突,编译器在编译阶段则报出了重定义错误。
这种问题在C语言里是没什么好的解决办法的,所以早期程序员上班的时候就会带一个锤子去上班,遇到这种命名冲突问题就带着武器去到天台干一架,谁能回来谁就可以使用这个名字。这种解决办法显然是不合理的,所以我们的祖师爷“Bjarne Stroustrup”在C++里增加了命名空间的特性,用来解决这种野蛮的处理问题方式
命名空间:
假设在一个项目里有程序员张三和李四,他们两个共同完成同一个项目的同一个功能模块,他们的编程习惯都很相似,变量的取名也大多相同。毫无疑问,这样会造成命名冲突,但是在C++他们就可以采用命名空间来完美的回避这个问题。
命名空间语法:
namespace <name>{
int x;
char c;
//...
}
放到项目中则是:
#include<iostream>
namespace zs {
int x;
char c;
}
namespace ls {
int x;
char c;
}
int main() {
zs::x = 10;//张三的x
ls::x = 20;//李四的x
printf("张三的x=%d\n", zs::x);
printf("李四的x=%d\n", ls::x);
}
运行结果:
命名空间特性的拆解:
首先认识一个符号 ::(域作用限定符)他用来声明使用那个命名空间的变量或者函数
域的概念:
我们知道全局变量和局部变量的区别,假设有全局变量x和局部变量x我们在局部变量的生命周期内优先使用的就是局部变量x,若在局部变量没找到x则会去全局搜索变量x,若找到了则通过编译,若没找到则报错。
我们的命名空间也是如此,在使用的时候默认在局部域先搜索变量,若没有则去全局搜索。但是在代码里我们可以指定直接去那个域找这个变量。这就是**:😗*的作用,如上边张三和李四的例子,变量在被域限定符限定后则不会再在局部和全局域找变量,直接去指定的命名空间找变量来使用。
域的展开:
设想一下,我们所有的变量都定义在命名空间,但是这个项目并不大,只是我们自己的手头练习罢了,基本不会出现明明冲突的可能性,但是每次使用都要加上::来限定是不是特别的麻烦呢,所以我们还有将命名空间权限展开的功能,这样被展开的域他就是一片公共的权限,每个在局部没搜索到的变量都可以在全局搜索到域内的变量,但是这种做法并不建议在大项目内使用,所以除了全部展开还有部分展开的使用,部分展开在大型项目比较常用。
全展开:
语法:
using namespace <name>;
eg:
#include<iostream>
using namespace std;
namespace zs {
int x;
char c;
}
namespace ls {
int x;
char c;
}
int main() {
zs::x = 10;//张三的x
ls::x = 20;//李四的x
cout << "张三的x=" << zs::x << endl;
std::cout << "张三的x=" << zs::x << std::endl;
}
运行结果:
这里还是需要说明下std这个命名空间是C++标准库的命名空间,比如在使用的控制台输出语句cout,他和printf其实是差不多的,但是cout是定义在std这个命名空间的,所以我们把访问权限放开以后就可以直接用cout,当然下边我也用了添加限定符的方式,其实是一样的。
部分展开:
语法:
using <name>::<val>;
这样便可以把某个空间内的某个值公开,其他的依然不受影响。
命名空间的合并:
若存在两个相同名字的命名空间,在编译时会被合并成一个命名空间
eg:
#include<iostream>
using namespace std;
namespace zs {
int x;
}
namespace zs {
char c;
}
int main() {
zs::x = 10;//张三的x
cout << "张三的x=" << zs::x << endl;
std::cout << "张三的x=" << zs::x << std::endl;
}
这种最后就会被合并为一个zs的命名空间,里边有int x 和char c。
命名空间的嵌套定义:
eg:
#include<iostream>
using namespace std;
namespace zs {
int x;
namespace test {
int x;
}
}
int main() {
zs::x = 10;//张三的x
zs::test::x = 20;
cout << "zs::x=" << zs::x << endl;
std::cout << "zs::test::x=" << zs::test::x << std::endl;
}
运行结果: