命名空间:给名字划分地盘

两个库都有 print(),怎么不打架?

商用

◎学完你会

1两个 print 打架:命名空间登场

两个库都想定义 print(),编译器会怎么裁决?切换下面的开关看对比。

点左边按钮开始。
不带命名空间时两个同名全局函数冲突,编译器直接报错;带命名空间后,用 Alpha::print / Beta::print 就能明确区分。

2关键命令

写法含义
namespace mylib { … }把里面所有名字放进 mylib 这个"地盘"
mylib::Foo();用 :: 明确调用某个地盘里的名字
namespace fs = std::filesystem;给命名空间起更短的别名 fs
using mylib::Foo;只把 Foo 这一个名字引入当前作用域(不是整个 mylib)
namespace { int helper; }匿名命名空间:里面的名字只在当前编译单元可见(内部链接)

3嵌套命名空间与别名

命名空间可以套命名空间,一层层像目录一样组织。

namespace myapp { namespace math { int add(int a, int b){ return a + b; } } } // 完整访问:myapp::math::add(1,2) namespace m = myapp::math; // 别名,敲起来省事 int r = m::add(1, 2); // r == 3
✅ 别名只是"另一个更短的名字",不复制任何东西,纯省打字。namespace fs = std::filesystem; 是 C++17 里最常用的别名。

4匿名命名空间 ≈ static(内部链接)

不写名字的命名空间,里面的名字只属于当前这一个 .cpp 文件,外面看不到。

namespace { int helper() { return 42; } // 只在本文件可见 } // 等价于(旧写法): static int helper2() { return 42; }
误区:把匿名命名空间写进头文件,并不会让所有包含它的文件共享这份代码——每个包含它的 .cpp 会各自编译一份,等于每份都是独立的,失去了"头文件里定义一次、处处共用"的意义。跨文件共享请用普通(有名字的)命名空间 + 声明。

5为什么头文件里别写 using namespace std

你自己写 using namespace std; 图方便,可头文件会被别人 #include。

// mylib.h —— 千万不要这么写 #pragma once using namespace std; // ← 谁 include 它,谁就被强制引入整个 std class mylib { … };
后果:你的头文件被 10 个 .cpp 包含,就等于强行往 10 个文件里塞了 using namespace std;。如果对方自己定义了叫 sort、cout 的名字,就和 std 撞车——污染所有包含者的命名空间。头文件里要用,就写 std:: 全限定,或只 using std::cout; 引入单个名字。

!易错点

① 头文件里写 using namespace std——污染所有包含者,是团队协作最易踩的坑。
② 匿名命名空间放头文件——每个 .cpp 各一份,失去共享意义。
③ 以为命名空间能解决"重复定义"——两个同名定义(不是声明)在链接期冲突,是链接问题;命名空间只在名字查找阶段帮忙,救不了重复定义。

?跨学科:命名空间,就是快递柜的"单元号"

一个小区里可能有两栋楼都有"1号柜"。光说"1号柜"没人知道你指哪个;说"3栋-1号柜"就清清楚楚——3栋 就是命名空间,:: 就是"的",1号柜 是里面的名字。

同理,图书馆用"楼层-书架-格号",公司用"部门-工位",都是把名字装进更大的空间来避免混淆。写代码给名字分地盘,和现实里给物品定位置,是同一种思维。

✎练一练

两个库都定义了全局 print(),哪个做法能解决冲突?
命名空间把同名名字放进不同"地盘",用 :: 就能明确区分,是解决撞名的正道。
namespace fs = std::filesystem; 这行代码的作用是?
namespace 别名 = 原名; 只是给命名空间换一个更短的名字,不复制、不引入任何名字。
把 namespace { int helper; } 写进一个会被多个 .cpp 包含的头文件,会发生什么?
匿名命名空间 = 内部链接,每个编译单元各一份。放进头文件反而每份都独立,失去共享意义。