命名空间
1.为什么会出现
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
printf("%d\n", rand);
return 0;
}
//编译后报错
//错误 C2365 “rand”: 重定义;以前的定义是“函数”
//重定义;以前的定义是“函数”(rand 随机数函数)
C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
#include<iostraem>
#include<stdlib.h>
namespace Room
{
int rand = 0;
}
int main()
{
printf("%d", Room::rand);
return 0;
}
//程序正常运行
2.命名空间如何定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
命名空间可定义变量、函数、类型
命名空间可以嵌套
namespace Room
{
//变量
int rand = 0;
//函数
int Add(int a, int b)
{
return a + b;
}
//类型
struct Node {
int val;
struct Node* Next;
};
//嵌套
namespace room
{
int b = 0;
int Sub(int a, int b)
{
return a - b;
}
struct NNode {
int val;
struct NNode* Next;
};
}
}
3.命名空间如何使用
① 加命名空间名称及作用域限定符(命名空间不展开)
作用域限定符 “::”
使用方式:命名空间名字 :: 命名空间内部变量、函数、或类型
其作用是通知编译器应从作用域限定符左侧的名字所示的作用域****中寻找右侧那个名字,即指定访问哪个名字空间的哪个成员。
#include<stdio.h>
namespace Room
{
//变量
int rand = 0;
//函数
int Add(int a, int b)
{
return a + b;
}
//类型
struct Node {
int val;
struct Node* Next;
};
//嵌套
namespace room
{
int b = 0;
int Sub(int a, int b)
{
return a - b;
}
struct NNode {
int val;
struct NNode* Next;
};
}
}
int main()
{
//访问变量
printf("%d\n", Room::rand);
//访问函数
printf("%d\n", Room::Add(1, 2));
//定义类型,域作用符在struct后
struct Room::Node NewNode;
NewNode.val = 0;
NewNode.Next = nullptr;//c++新增关键字 空指针NULL的升级版
printf("%d\n", NewNode.val);
//访问嵌套命名空间的变量
printf("%d\n", Room::room::b);
//访问嵌套命名空间的函数
printf("%d\n", Room::room::Sub(2, 1));
//访问嵌套命名空间的类型
struct Room::room::NNode NNewNode;
NNewNode.val = 0;
NNewNode.Next = nullptr;
printf("%d\n", NNewNode.val);
return 0;
}
②使用using将命名空间中某个成员引入(命名空间部分展开)
using 命名空间名字 :: 命名空间内部变量、函数、或类型
将其展开,使其成为一个全局变量。
#include<stdio.h>
//展开命名空间内部的变量
using Room::a;
//展开命名空间内部的函数
using Room::Add;
//展开命名空间内部的类型
using Room::Node1;
namespace Room
{
int a = 0;
int b = 1;
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
struct Node1 {
int val;
struct Node1* Next;
};
struct Node2 {
int val;
struct Node1* Next;
};
}
int main()
{
//变量a被展开,不需要域作用符
//变量b未被展开,需要域作用符
printf("%d\n", a);
printf("%d\n", Room::b);
//函数Add被展开,不需要域作用符
//函数Sub未被展开,需要域作用符
printf("%d\n", Add(1, 2));
printf("%d\n", Room::Sub(2, 1));
//类型Node1被展开,不需要域作用符
//类型Node2未被展开,需要域作用符
struct Node1 NewNode1;
NewNode1.val = 0;
struct Room::Node2 NewNode2;
NewNode2.val = 0;
return 0;
}
③使用using namespace 命名空间名称引入(命名空间全部展开)
using namespace 命名空间名字
#include<stdio.h>
using namespace Room;
namespace Room
{
//变量
int rand = 0;
//函数
int Add(int a, int b)
{
return a + b;
}
//类型
struct Node {
int val;
struct Node* Next;
};
//嵌套
namespace room
{
int b = 0;
int Sub(int a, int b)
{
return a - b;
}
struct NNode {
int val;
struct NNode* Next;
};
}
}
int main()
{
//访问变量
printf("%d\n", rand);
//访问函数
printf("%d\n", Add(1, 2));
//定义类型,域作用符在struct后
struct Node NewNode;
NewNode.val = 0;
NewNode.Next = nullptr;
printf("%d\n", NewNode.val);
//展开的是命名空间Room,不需要struct Room::room::NNode NNewNode;
//但是struct NNode在room之中仍需要room::NNode
struct room::NNode NNewNode;
NNewNode.val = 0;
NNewNode.Next = nullptr;
printf("%d\n", NNewNode.val);
return 0;
}
同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
一个工程中的test.h和上面test.cpp中两个Room会被合并成一个