命名空间(namespace)
0.使用方法
namespace 命名空间名 {
...
}
1. 每个命名空间都是一个作用域
同其他作用域类似,命名空间中的每个名字都必须表示该空间内的唯一实体。因为不同命名空间的作用域不同,所以在不同命名空间内可以有相同名字的成员。
#include<iostream>
namespace self_space1 { // 定义命名空间self_space1
int num = 1;
}
namespace self_space2 { // 定义命名空间self_space2
int num = 2;
}
// self_space1与self_space2是两个不同的命名空间
int main() {
std::cout << self_space1::num << std::endl; // 输出1
std::cout << self_space2::num << std::endl; // 输出2
}
2. 命名空间可以不连续
命名空间的定义可以不连续的特性使得我们可以将几个独立的接口和实现文件组成一个命名空间,定义多个类型不相关的命名空间也应该使用单独的文件分别表示每个类型。
命名空间可以在几个部分中分开定义,即命名空间是累计的。一个命名空间可以分散在多个文件中。如下代码所示。
namespace self_space1 { // 定义命名空间self_space1
int num = 1;
}
namespace self_space2 { // 定义命名空间self_space2
int num = 2;
}
3. 全局命名空间
全局作用域中定义的名字(即在所有类、函数以及命名空间之外定义的名字)也就是定义在全局命名空间global namespace
中。全局作用域是隐式的,所以它并没有名字,下面的形式表示全局命名空间中一个成员:
::member_name
给出示例,如下所示。
#include<iostream>
int num = 1;
int main() {
std::cout << ::num << std::endl; // 输出1
}
4. 嵌套的命名空间
命名空间是可以嵌套的,并且如果两个命名空间里面定义相同名字的变量,这两个变量名是不冲突的。如下代码所示。
namespace foo {
namespace bar {
int num;
}
}
// 常用调用方式
foo::bar::num
如果我们要访问命名空间里嵌套的命名空间的变量该如何访问呢?给出如下示例。
方法一:
/*命名空间的嵌套使用*/
#include <iostream>
using namespace std;
namespace self_space1 { // 定义一个self_space1的嵌套空间
namespace self_space2 {
int num = 3;
}
}
//方法一
int main() {
cout << self_space1::self_space2::num << endl; // 输出3
return 0;
}
方法二:
/*命名空间的嵌套使用*/
#include <iostream>
using namespace std;
namespace self_space1 { // 定义一个self_space的嵌套空间
namespace self_space2 {
int num = 3;
}
}
// 方法二
using namespace self_space1; // 展开命名空间self_space1
int main() {
cout << self_space2::num << endl; // 输出3
return 0;
}
5.命名空间的合并
如果我们在多个文件里面定义同一个命名空间,会自动合成一个命名空间(前提是这两个命名空间中的变量名不相同)。如下代码所示。
namespace.h 文件中的代码如下所示。
C++cin_cout.cpp 文件中的代码如下所示。
运行C++cin_cout.cpp文件中的程序,结果如上图所示。
如果定义同名的变量,会发生冲突。
我们分别在namespace.h文件与C++cin_out.cpp两个不同的文件中定义命名空间namespace,在空间中我们定义相同的变量num,如下代码所示。这样定义的结果是,num变量被多次初始化,程序报错。
结果报错,错误原因如下:
全局域及局部域
示例:全局域及局部域的对比
#include <iostream>
using namespace std;
int num = 2; // 全局变量num
int main() {
int num = 1; // 局部变量num
cout << num; // 根据局部变量优先原则,程序输出1
return 0;
}
上述代码运行结果为1,即将第二个num (局部变量) 打印出。如果我们想将第一个num (值为2) 打印出,该如何呢?
这个时候我们只需要考虑域作用限定,即在cout << num;中的num前面加上::,如下代码所示。
#include <iostream>
using namespace std;
int num = 2; // 全局变量num
int main() {
int num = 1; // 局部变量num
cout << num << endl; // 根据局部变量优先原则,该条语句输出1
cout << ::num; // 全局域限定,该条语句输出2
return 0;
}
上述代码中第一条cout语句打印结果为1,第二条cout语句打印结果为2,cout << ::num;输出2的原因是num前面的::作用。
命名空间域
一般情况下,一个项目都是多个人共同去完成,假设A人已经定义了一个变量a,而B人也想定义一个a变量,这个时候该如何呢?
办法是:使用命名空间(namespace),如下代码段所示,在该代码段中,我们使用namespace定义了一个名为self_space的空间,在该空间中,我们定义了一个int型的变量num,其赋值为3。
namespace self_space{ // 定义一个self_space的空间
int num = 3;
}
命名空间会把里面定义的变量和外面的变量隔离开来,编译器不会主动访问命名空间。
如果我们想要访问命名空间中的变量,即上述命名空间self_space中的变量num,该如何呢?
方法:
法一:在::(域作用限定)前面加上命名空间的名字即可访问,即self_space::num即可,如下代码所示。
#include <iostream>
using namespace std;
namespace self_space{ // 定义一个self_space的空间
int num = 3;
}
int num = 2; // 全局变量num
int main() {
int num = 1; // 局部变量num
cout << num << endl; // 根据局部变量优先原则,该条语句输出1
cout << ::num << endl; // 全局域限定,该条语句输出2
cout << self_space::num; // 该条语句输出3,输出命名空间self_space中的num变量
return 0;
}
法二:展开命名空间,展开之后不需要指定访问。
#include <iostream>
using namespace std;
namespace self_space { // 定义一个self_space的空间
int num = 3;
}
using namespace self_space; // 使用命名空间self_space
int main() {
cout << num << endl; // 该条语句输出3
return 0;
}
命名空间的变量与全局变量冲突问题
若我们创建了一个全局变量num,又在命名空间self_space中创建了一个变量num,并且将命名空间self_space展开,则会优先访问哪一个变量num呢?答案是程序会报错,错误为变量num不明确。如下代码所示。
为什么会报错呢?因为展开的意思就是暴露到全局,也就是和全局冲突了,编译器也不知道访问哪个了,所以using namespace不要轻易去用,因为命名空间就是为了解决命名冲突,结果你把它暴露到全局那不就毫无意义了吗?
我们从上面能发现一个什么结论呢?优先访问局部域,然后是全局域、展开命名空间或者指定访问域。
std
使用方法:
using namespace std;
有些人写C++的时候会写上面一句代码,那这个代码是什么意思呢?很显然,展开了名为std的命名空间,C++库里面的东西都在std这个命名空间里面,展开之后加上头文件才可以使用C++库里面的东西,但是我们把它们全都展开了好不好?答案是不好,因为这样容易发生命名冲突,这在上述例子中我们已经展示。所以我建议如果写项目不要全展开,指定展开。用什么展开什么,比如我要用cout就展开cout。
即using std::cout;
在日常练习中可全部展开。
部分参考自:
C++入门(命名空间和std)_c++ std_花与剑与花的博客-CSDN博客