1.应用领域:
服务器端,游戏引擎,机器学习引擎,音视频处理,嵌入式软件,电信设备,金融应用,基础库,操作系统,编译器,基础架构,基础工具,硬件互动等
2.命名空间:
命名空间是 C++ 用于隔离标识符名称的语法机制,本质是划定一块独立作用域,将变量、函数、类等标识符收纳在这个作用域内,用来解决多文件协作、引入第三方库时产生的命名冲突问题。命名空间仅在编译期生效,本身不占用内存,还可以为较长的命名空间定义别名,简化代码书写。命名空间内部的成员不会自动暴露到外部,访问成员时需要通过命名空间名称进行限定。
在C语言中可能会与库函数名出现冲突,C++的命名空间namespace则可以顺利解决该问题
2.1定义命名空间:
要用到namespace关键字,后面跟有命名空间的名字,然后接一对{},{}中即为命名空间的成员,命名空间中可以定义变量,函数,甚至结构体等等
namespace N
{
typedef int STDataType;
// 动态顺序栈结构体
typedef struct Stack
{
STDataType* a; // 动态数组,存放栈元素
int top; // 栈顶标记,代表下一个要入栈的位置
int capacity; // 数组总容量
}ST;
// 栈接口声明
void STInit(ST* ps, int n);
void STDestroy(ST* ps);
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
STDataType STTop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);
}
// Stack.cpp,函数的定义
#include"Stack.h"
namespace bit
{
// 栈初始化,预开辟n个元素的空间
void STInit(ST* ps, int n)
{
assert(ps);
ps->a = (STDataType*)malloc(n * sizeof(STDataType));
ps->top = 0;
ps->capacity = n;
}
// 入栈
void STPush(ST* ps, STDataType x)
{
assert(ps);
// 判断栈是否已满,满则扩容
if (ps->top == ps->capacity)
{
printf("扩容\\n");
// 空栈初始给4,否则容量翻倍
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity = newcapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
// 其余栈接口:STPop、STTop、STSize、STEmpty、STDestroy 省略
}
//全局变量的使用和命名空间namespace的使用区别
// 全局版本栈的函数
void STInit(ST* ps) {}
void STPush(ST* ps, int x) {}
int main()
{
// 使用【全局】的ST结构体与函数
ST st1;
STInit(&st1);
STPush(&st1, 1);
STPush(&st1, 2);
printf("%d\\n", sizeof(st1));
// 使用【bit命名空间】内的ST结构体与函数,用::访问
bit::ST st2;
printf("%d\\n", sizeof(st2));
bit::STInit(&st2);
bit::STPush(&st2, 1);
bit::STPush(&st2, 2);
return 0;
}
2.2命名空间namespace本质:
其本质是一个域,该域与全局域相互独立,不同的域可以定义同名变量,不会产生同命名冲突
int x = 0;
namespace A {
int x = 1;
}
namespace B {
int x = 2;
}
::x // 全局的 x,在::域作用限定符前无指定域,故指向全局域
A::x // A 里的 x
B::x // B 里的 x
2.3C++的域:
C++的域有函数局部域,全局域,命名空间域,类域,域影响的是编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期。
C++ 标准库的所有接口就统一放置在 std 命名空间中。
2.4注意:
命名空间只能定义在全局,命名空间内可以进行嵌套定义(要从外向内进行指定域)
namespace A {
namespace B {
int x = 0;
}
namespace C {
int x = 10;
}
}
int main() {
printf("%d\\n", A::B::x);
printf("%d\\n", A::C::x);
}
注意嵌套层级关系:这里 A::N 和 ::N 是两个不同的命名空间,不会合并。
namespace A {
namespace N {
int x;
}
}
namespace N {
int y;
}
2.5多文件中定义同名namespace,编译器会自动合并,视为同一个命名空间
// a.cpp
namespace N {
void f() {}
}
// b.cpp
namespace N {
void g() {}
}
//等效于
// main.cpp
namespace N {
void f();
void g();
}
int main() {
N::f();
N::g();
}
//同一个文件下,也可适用
namespace N {
int a;
}
namespace N {
int b;
}
//等效于
namespace N {
int a;
int b;
}
注意:但要注意,合并的是命名空间本身,不是里面的实体。也就是说:
namespace N {
int x;
}
namespace N {
int x; // 错误:同一个 N 中重复定义 x
}
但是可以这样:因为这是同一个函数的声明和定义。
namespace N {
void f(); // 声明
}
namespace N {
void f() {} // 定义
}
2.6其他:
使用命名空间仍存在需要留意的地方,如:
不要在头文件中使用 using namespace 指令,头文件 会被多个源文件包含,会大范围引入命名空间标识符,极易引发命名冲突;
使用 using 声明或者 using 指令时,其作用范围仅限于当前作用域,不会向外扩散;
命名空间只隔离名字,命名空间内部定义的全局变量依旧拥有全局生命周期;
工程开发中不建议滥用 using namespace std,优先使用 std:: 限定的方式访问标准库成员,降低命名冲突的风险。
2.7域的查找规则
情景一:无指定域
先在局部域中查找(当前所在域中),再在全局域中查找
namespace A {
int rand = 10;
int ADD(int a, int b) {
return a + b;
}
struct Node {
struct Node* next;
int data;
};
}
int main() {
printf("%d\\n", rand);//rand是在库函数中,未指定域,在这里直接打印出的是rand函数地址的十进制
printf("%d\\n", A::rand);//指定是A所在域的rand=10
}

情景二:有指定域
现在指定域中查找,再去所在的局部域中查找,最后在全局域中查找
3.命名空间namespace使用
编译查找一个声明或者定义时,默认只会在全局或者局部中查找,不会在命名空间域中查找,所以要使用命名空间中定义的变量或者函数等等,有三种形式:
Ⅰ:指定命名空间访问(大量访问时不推荐使用)
namespace A {
int x = 1;
}
namespace B {
int x = 2;
}
int main() {
int a = A::x; // 访问 A 中的 x
int b = B::x; // 访问 B 中的 x
}
Ⅱ:using将命名空间中某个成员展开(项目中访问某个常用且不存在冲突的成员时推荐)
如using A::STPush()是一种部分展开
这种写法会在局部域中查找,全局域中查找,命名空间域中查找(使用命名空间内的函数或者变量,无需再去写A::XX)
using std::cout; // using 声明:只引入 cout
using namespace std; // using 指令:引入整个 std 命名空间
注意:会和局部域或者其他域中同名的变量出现冲突
namespace N { int x; }
int main() {
using N::x;
int x = 1; // 错误:重复定义
}
Ⅲ:展开命名空间的全部成员(项目中不推荐,冲突风险大)
写法:using namespace 命名空间名;
缺点:会把指定命名空间中的全部成员名字引入当前作用域,让它们在未限定名字查找中可见。
namespace N {
int x;
void f();
}
using namespace N;
int main() {
x = 1; // 可以,相当于找到 N::x
f(); // 可以,相当于找到 N::f
}
理解:
using namespace A; 不是把 A 的成员复制到当前命名空间,也不是让它们变成当前命名空间的成员。它只是影响名字查找:
-
从 using namespace A; 出现的位置开始;
-
到它所在作用域结束;
-
这期间写未限定名时,编译器会把 N 中的名字也纳入查找范围。
注意:
//错误写法
namespace N { int x; }
namespace X { using namespace N; }
X::x; // 一般不行,x 并不是 X 的成员
//正确写法
x; // 在 X 作用域内,可能通过未限定查找找到 N::x
N::x; // 显式限定,总是可以
//产生命名歧义
namespace A { int x; }
namespace B { int x; }
using namespace A;
using namespace B;
int main() {
x = 1; // 错误:A::x 还是 B::x?
}
//纠正
A::x = 1;
B::x = 2;
综上所述:
项目中更推荐 using N::member; 或直接写 N::member,避免在头文件和全局作用域使用 using namespace。

![set 与 map :从 [] 暗坑到严格弱序,把有序关联容器用明白-171主机测评](https://www.171host.com/wp-content/uploads/2026/10/20261031153944-6ae60bc0ee6df-220x150.png)

