C++ 用命名空间把函数、类、变量的名字圈在一组里,避免两个库都提供 log 时互相覆盖。本质是给名字加前缀:app::log 与 util::log 可以并存。标准库的名字都在 std 里,所以教程里写 std::cout 而不是裸的 cout。C 语言没有命名空间,习惯用前缀区分(如 gtk_widget_show);C++ 把前缀写成语法。本节先演示同名并存,再说明 using、嵌套与匿名命名空间。头文件中不要写 using namespace std;,见头文件与多文件。
log 放进不同命名空间后不再冲突。最简单的例子
若在全局作用域写两个 void log(),程序无法通过编译。放进不同命名空间后,用 :: 写明要哪一个:
#include <iostream>
namespace app {
void log() {
std::cout << "app\n";
}
}
namespace util {
void log() {
std::cout << "util\n";
}
}
int main() {
app::log(); // 调用 app 里的 log
util::log(); // 调用 util 里的 log
return 0;
}输出:
app
utilstd::cout 也是同一规则:cout 定义在命名空间 std 中。
using 声明与 using 指令
using app::log; 只引入一个名字,此后在当前作用域可直接写 log(),仍等于 app::log()。using namespace std; 则把 std 里大量名字一并引入,容易与自己的 count、list 等撞名。头文件一旦写后者,所有包含该头文件的代码都会被污染,因此公开头文件应写全 std::。
#include <iostream>
namespace app {
void log() {
std::cout << "app\n";
}
}
namespace util {
void log() {
std::cout << "util\n";
}
}
int main() {
using app::log; // 只引入 app::log
log();
util::log(); // 另一个仍须写限定名
return 0;
}输出:
app
util实现文件的函数体内写 using std::cout; 可以接受;不宜在全局作用域长期 using namespace std;。C++11 的 using Id = int; 是类型别名,与这里的 using 声明不是同一件事,见以后别名与模板章节。
嵌套命名空间
命名空间可以套在另一层里面,调用时写两层限定名。C++17 允许写成 namespace app::util { ... },与先写 namespace app { namespace util { ... } } 等价:
namespace app::util {
void log(const char* msg) {
std::cout << "[log] " << msg << std::endl;
}
}
int main() {
app::util::log("started");
return 0;
}匿名命名空间
不写名字的 namespace { ... } 表示这些名字只给本文件用。其他 .cpp 即使出现同名变量,也不是同一个对象。C 语言里文件内 static 全局变量起类似作用。
#include <iostream>
namespace {
int n = 0; // 仅本文件可见
}
void bump() {
++n;
}
int main() {
bump();
bump();
std::cout << n << "\n";
return 0;
}输出:
2不要在头文件里用匿名命名空间定义普通对象:每个包含该头文件的 .cpp 都会得到一份独立副本。
与头文件、std
头文件中声明的函数和类应放在项目自己的命名空间内,减少与第三方库及 std 的冲突。头文件不要写 using namespace std; 或 using namespace app;。本站在线编译一次只处理一份源码,多文件工程仍须在本地把声明放进命名空间、在实现文件里用限定名定义,见头文件与多文件。
了解:内联命名空间与 ADL
inline namespace 常用于给库做版本,调用时可以不写版本那一层名字,初学以普通命名空间为主。参数依赖查找(ADL)是:写 swap(a, b) 且未加 std:: 时,编译器还会到 a、b 所属类型的命名空间里找 swap。泛型库会用到这一点,入门程序把名字写全即可。
本节说明了用命名空间组织名字、避免冲突的基本写法。下一章从函数模板与类模板开始,介绍泛型编程入门。