关于c++:浅谈C命名空间的一些陷阱

43次阅读

共计 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 namespaceusing 关键字引入一个或多个命名空间,也能够应用作用域限定符拜访命名空间中的标识符。

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 就在路上等着, 你可能害了整个团队, 让一个上游程序员莫名微妙的追踪 数百乃至数万个编译报错, 践踏并撕扯下他本就所剩无几的头发.

正文完
 0