在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存
在于全局作用域中,可能会导致很多冲突。
命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
一.概念
命名空间的原理是将全局作用域划分为一个一个的命名空间,每个命名空间是一个独立的作用域,在不同命名空间内部定义的名字彼此之间互不影响,从而有效的避免了命名空间污染。
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
printf("%d\n", rand);
return 0;
}
rand在c中是一个函数,而我们现在又将它作为变量定义,在编译时就会出现错误。C无法解决这种问题,所以C++使用namespace(命名空间)来解决。
二.定义
namespace 命名空间名
{
.......
}
1.命名空间名的名字可以自己定义。
2.命名空间中可以定义变量/函数/类型。
3.命名空间可以在全局作用域或其他命名空间内部定义,但不能在函数、结构体或类内部定义,且要保证命名空间之间不会出现名字冲突。
4.同一命名空间不能有相同名字,不同命名空间可以有相同名字。
5.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中,所以说,不同文件中的名字相同的命名空间中也不能有相同名字的空间成员。
6.一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。
这里我们需要了解编译器的默认查找:1.局部查找 2.全局查找 3.命名空间中查找(仅限声明时)
三.使用
命名空间有三种不同的使用方式
1.加命名空间名称及作用域限定符
#include<iostream>
namespace shz
{
int rand = 10;
}
int main()
{
printf("%d ", shz::rand);
return 0;
}
该方式只对当前变量的作用域有效
域名限定符前为空表示忽略局部优先,指定全局域变量。
2.使用using将命名空间中某个成员引入
#include<iostream>
namespace shz
{
int a = 10;
int b = 20;
}
using shz::b;
int main()
{
printf("%d\n", shz::a);
printf("%d ", b);
return 0;
}
using N::b;可以写在源文件的任意位置,函数内外、前后都可以。
引入后的成员从引入位置开始向下具有全局作用域,可以跨函数使用。
3.使用using namespace 命名空间名称 引入
#include<iostream>
namespace shz
{
int a = 10;
int b = 20;
}
using shz::b;
using namespace shz;
int main()
{
printf("%d\n", shz::a);
printf("%d\n", b);
printf("%d\n", a);
return 0;
}
这种方法不推荐使用,因为将整个命名空间展开会使命名隔离失效,也就违背了我们使用命名空间的初衷。
using namespce N;可以写在源文件的任意位置,函数内外、前后都可以。但一般写在文件头。
引入后的命名空间从引入位置开始向下具有全局作用域,可以跨函数使用。
四.嵌套
#include<iostream>
namespace shz
{
int a = 10;
int b = 20;
namespace fly
{
int Add(int x, int y)
{
return x + y;
}
namespace cat
{
struct ST
{
int* arr;
int size;
int capacity;
};
}
}
}
using shz::b;
using namespace shz;
int main()
{
printf("%d\n", shz::a);
printf("%d\n", b);
printf("%d\n", a);
printf("%d\n", shz::fly::Add(10, 20));
return 0;
}
对于嵌套定义的命名空间在使用时要层层向下调用:shz::fly::Add(10,20);
之前学过的变量作用域在命名空间中同样适用:
允许父子空间定义同名变量,变量在各自定义的空间中起作用。
父空间中定义的变量(非同名变量)可以在子空间中直接作用,但子空间中定义的变量不能在父空间中直接作用。
父空间使用子空间中定义的变量需要引用对应的命名空间,但可以不带父空间名。