命名空间通过namespace关键字定义,后跟名称和花括号,内部可包含类、函数、变量等成员;支持嵌套,同名命名空间可合并;类定义需整体置于花括号内,不可写namespace::classname。

类定义直接写在命名空间花括号内
最常见也最直观的方式,就是把整个 class 定义(包括声明和可选的 inline 成员函数)包进 namespace 里。编译器会把类名、成员名都绑定到该命名空间下,不会污染全局作用域。
注意:类名本身不带命名空间前缀——前缀只在使用时体现;定义时不能写 namespace::ClassName 这种形式,那是错误语法。
- 正确写法:
namespace math { class Vector2 { public: double x, y; Vector2(double x = 0, double y = 0) : x(x), y(y) {} }; } - 错误写法:
namespace math::Vector2 { ... }或class math::Vector2 { ... } - 如果类体很大,建议把声明放头文件(
.h),定义放源文件(.cpp),此时需在两个地方都显式进入同一命名空间
在命名空间外定义成员函数必须加作用域解析符
当把成员函数声明留在命名空间内、但实现(定义)挪到命名空间外时,必须用 :: 明确指出它属于哪个命名空间里的哪个类。否则编译器找不到对应声明,报 no declaration matches 或 undefined reference。
- 头文件中:
namespace graphics { class Renderer { public: void draw(); }; } - 源文件中(必须重复命名空间路径):
namespace graphics { void Renderer::draw() { /* 实现 */ } }或者更常见的是:void graphics::Renderer::draw() { /* 实现 */ } - 漏写
graphics::会导致链接失败;写成::Renderer::draw()是错的——那表示全局命名空间里的Renderer
嵌套命名空间里放类要注意作用域链
C++17 支持嵌套命名空间简写(如 namespace a::b::c),但类一旦定义在里面,它的“全名”就包含所有层级。使用时要么用完整限定名,要么用 using 引入。
- 定义:
namespace engine::render { class Framebuffer { /* ... */ }; } - 使用方式:
engine::render::Framebuffer fb;,或在函数内加using engine::render::Framebuffer; - 不能只写
using namespace render;——因为render不在全局作用域,得先有using namespace engine;才能访问其子空间(C++ 标准不支持跨级 using 子空间) - 如果多个嵌套层都有同名类(比如
engine::v1::Renderer和engine::v2::Renderer),靠命名空间隔离比靠类名后缀更清晰
模板类放进命名空间要小心友元和特化
模板类放入命名空间后,其特化、友元声明、ADL(参数依赖查找)行为都会受命名空间影响。最容易出问题的是友元函数声明——它默认在当前命名空间里找,而不是全局。
- 若在
namespace io中定义template<typename t> class Buffer</typename>,又想给它加一个友元operator,这个 <code>operator 必须也定义在 <code>io命名空间里,否则无法被 ADL 找到 - 偏特化必须和主模板在同一个命名空间,且写法为:
namespace io { template class Buffer<char> { /* ... */ }; }</char> - 全特化可以放在任意命名空间,但推荐仍放在原命名空间,避免使用者意外调用到错误版本
命名空间不是装饰,它参与符号查找全过程。类一放进命名空间,它的名字就“变长了”,所有引用点、特化点、友元点都得同步对齐——少一个冒号,可能就是编译不过或静默调用错版本。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











