一、写在前面
对比 C 语言,一般 C++ 每增加一个语法都是为了解决一些 C 语言做不到的事或者是 C 语言做的不好的地方
在 C/C++ 中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace 关键字的出现就是针对这种问题的。
❗ C语言命名冲突示例 ❕
在不同的作用域中,可以定义同名的变量;在同一作用域下,不能定义同名的变量
#include<stdio.h> //#include<stdlib.h> int a = 0; int rand = 10; int main() { int a = 1; printf("%d\n", rand); return 0; }
📝 分析:
可以看到我们定义了一个 rand 变量输出是没有问题的,但如果包含了 stdlib 头时就会产生命名冲突,此时我们的 rand 变量就和库里的产生冲突;
实际除此之外在大型项目开发时,还有可能和同事之间发生冲突。C 语言面对这种问题是无法解决的,而对于这种场景 C++ 使用了命名空间
二、命名空间定义
定义命名空间,需要使用到 namespace 关键字,后面跟命名空间的名字,然后接一对 {} 即可,{} 中即为命名空间的成员
⚠ 注意一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
//1. 普通的命名空间 namespace N1 // N1为命名空间的名称 { //命名空间中的内容,既可以定义变量,也可以定义函数 int a; int Add(int left, int right) { return left + right; } } //2. 命名空间可以嵌套 namespace N2 { int a; int b; int Add(int left, int right) { return left + right; } namespace N3 { int c; int d; int Sub(int left, int right) { return left - right; } } } //3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中 namespace N1 { int a = 10; } namespace N1 { int b = 20; }
❗ 用命名空间解决变量 rand 和 stdlib 库里的命名冲突 ❕
#include<stdio.h> #include<stdlib.h> namespace WD//定义了一个命名空间域 { int rand = 10;//定义变量 int Add(int x, int y)//定义函数 { return x + y; } struct Node//定义结构体类型 { struct Node* next; int val; }; } int main() { printf("%p\n", rand);//函数指针 printf("%d\n", WD::rand);//rand变量;‘::’叫做域作用限定符 WD::Add(3, 5);//调用函数 struct WD::Node node1;//结构体 return 0; }
❗ 嵌套命名空间 ❕
#include<stdio.h> #include<stdlib.h> namespace WD { int w = 20; int h = 10; namespace WH//嵌套命名空间域 { int w = 10; int h = 20; } } int main() { printf("%d\n", WD::WH::h);//访问嵌套命名空间 return 0; }
❗ 相同名称的命名空间 ❕
namespace WD { int a = 10; int b = 20; namespace WH { int a = 20; int b = 10; } } namespace WD//相同名称的命名空间 { int rand = 50; //int a = 10;//err,在合并的时候冲突了 }
三、命名空间使用
❓ 如何使用命名空间里的东西 ❔
1️⃣ 全部直接展开到全局
using namespace WD; //using namespace std;//std是包含C++标准库的命名空间
💨优点:用起来方便
💨缺点:自己定义的东西也会暴露,导致命名污染
2️⃣ 访问每个命名空间中的东西时,指定命名空间
std::rand;
💨优点:不存在命名污染
💨缺点:如果要去访问多个命名空间里的东西时,需要一一指定
3️⃣ 仅展开常用的内容
using WD::Node; using WD::Add;
💨优点:不会造成大面积的污染;把常用的展开后,也不需要一一指定
namespace WD { int a = 10; int b = 20; //... } int main() { //using namespace WD;//1.展开WD空间所有内容 //printf("%d\n", WD::a);//2.指定命名空间 //using WD::a;//3.仅展开a }
❓ 上面说了 C++ 把库里的东西都放到 std 这个域里了,那直接展开 std 不就行了或者包头 ❔
注意
1️⃣ #include <iostream>:展开定义
2️⃣ using namespace std;:允许用
所以两者缺一不可