共计 1578 个字符,预计需要花费 4 分钟才能阅读完成。
前言
最近看到个问题, 就是在命名空间中申明一个变量 (int rand = 0), 用 using namespace 将这个命名空间引入 ( 净化
) 进全局空间, 当函数调用此变量时产生谬误.
这是命名空间全局净化典型案例, 咱们进行一些分析
一、命名空间是什么?
C++ 命名空间(namespace)是一种将全局作用域宰割为若干个小的作用域的机制。
它能够解决命名抵触(name clash)的问题,使不同作用域下的同名标识符互不烦扰。
命名空间的应用办法如下:
1. 定义命名空间:能够在全局空间下定义命名空间,也能够在已有的命名空间内定义子命名空间,例如:
namespace math
{int add(int a, int b)
{return a + b;}
namespace geometry
{double circle_area(double r)
{return 3.14159 * r * r;}
} // namespace geometry
} // namespace math
2. 应用命名空间:能够用 using namespace
或 using
关键字引入一个或多个命名空间,也能够应用作用域限定符拜访命名空间中的标识符。
using namespace math; // 引入 math 命名空间
using math::geometry::circle_area; // 仅引入 math::geometry::circle_area 标识符
int main()
{int sum = math::add(1, 2); // 应用作用域限定符拜访 math 命名空间中的函数
double area = circle_area(10.0); // 间接应用 circle_area 标识符(已引入)return 0;
}
二、命名空间全局净化
命名空间是一种避免变量和函数因名称反复, 导致程序失败的机制。
全局净化是指太多的变量和函数被定义在全局命名空间中,容易产生命名抵触和相互烦扰,从而导致程序呈现谬误。
通过应用命名空间,能够将变量和函数封装到特定的命名空间中,以防止与其余变量和函数抵触。
这进步了代码的可维护性和可读性,并使代码更易于了解和批改。
然而, 有一种不良的编程习惯, 就是将命名空间引入全局, 导致 全局净化
的产生.
以下是一个示例
#include <iostream>
namespace hk
{int rand = 0;}
using namespace hk;
auto main() -> int
{auto a = rand;}
代码中, hk 作为一个命名空间, 被引入到全局, 而后咱们诧异的发现, 程序中的 rand 产生了抵触, 编译器无奈辨认, rand 到底是一个 int 对象还是一个函数指针.
认真分析, 发现, rand 自身是一个库函数, 当 hk 净化进全局, 作为 int 对象的 rand 和 函数名 rand 抵触了.
只是咱们没有引入过与 rand 函数相干的头文件, 这个 rand 又是哪里来的?
这就是 C ++ 的要命之处, 头文件的互相援用.
咱们只是引入<iostream>
, 而它又援用其余头文件, 其余头文件不知援用了多少次之后, 援用了 <stdlib.h>
头文件, 是的, 你无奈晓得你的实现代码中到底援用了什么.
这也是为什么, C++ 的前辈通知咱们, 永远不要应用 using namespace
将命名空间引入全局的起因, 这与命名空间的初衷南辕北辙, 它是用来解决命名抵触问题的, 不是引入命名抵触问题的.
所以, 在偷懒的时候, 肯定要晓得偷懒可能产生的代价.
为了解决上述问题, 代码不得不改为:
auto main() -> int
{
auto a = hk::rand;
auto b = ::rand;
}
总结
有时候, 前人总结的教训不肯定立即起到作用, 比方, 相对不要 人为引入全局空间净化
,
但当你违反以上正告, 却没有产生问题, 还貌似进步了打字效率,
殊不知, 各种莫名微妙的 bug 就在路上等着, 你可能害了整个团队, 让一个上游程序员莫名微妙的追踪 数百乃至数万个编译报错
, 践踏并撕扯下他本就所剩无几的头发.