【问题标题】:Why are namespaces used?为什么要使用命名空间?
【发布时间】:2025-12-08 06:05:01
【问题描述】:

这让我很困惑。所有代码示例为namespaceAnamespaceB,方法名称为foo()bar() 也无济于事。每个人都解释它的方式看起来好像命名空间是前 OOP 时代的遗迹,你不能说“一流的汽车给燃料水平”,但不得不从另一种方法来解决这个问题。但是当我现在想做一个 C++ 级别时,使用命名空间有什么意义呢?并不是说标题已经足够令人困惑,命名空间对我来说绝对没有意义,无论它们是如何工作的,或者为什么要使用它们。

例如,假设我有一个围绕Traffic 构建的项目。您将拥有Cars 及其组件、Drivers 和Passengers 以及Road 的类。 现在,RoadCars,每个CarPersons。这会是什么样子?

你有命名空间RoadCarPerson吗? main() 会使用命名空间Road 来访问标题中的内容吗?命名空间Road 是否包含命名空间Car,而Car 是否包含命名空间Person,并且main() 是否可以通过此访问Person 中的方法?大多数指南都是这样解释的,但是我真的看不出这比只导入头文件有什么好处,那不是有同样的效果吗?

或者您会将多个标头放在同一个命名空间中,例如 namespace Traffic 与所有这些类?可以嵌套命名空间吗?

我知道 C#,但直到我刚才查找它时才知道它有命名空间,并且从不需要它,而在 Java、Python 和 Dart 中,这些也从未出现过。由于我想自学 C++,所以我现在有点困在这里,在这里问这个问题。到目前为止,我也从未在 C++ 中使用过它们,但我想好好学习它。

【问题讨论】:

  • 在 Java、Python 和 Dart 中也从未出现过 Python 模块创建隐式命名空间。我不了解 Java 和 Dart。
  • Java 有包,还有那些分区名称
  • 在您的 Road/Car/Person 示例中,我希望这些类可能位于名为 Models 或类似性质的名称空间中。无法想象您为什么要为每个类创建一个命名空间,因为其目的是在逻辑上将类组合在一起。
  • 在 C++ 为语言添加命名空间之前,有些人会使用结构作为临时命名空间,以帮助收集和组织组件。但这有一些命名空间没有的不良行为,因此在 C++ 的演变过程中,namespace 被正式添加到语言中,标准 C++ 库被放入 ::std 命名空间。

标签: c++ header namespaces


【解决方案1】:

对于小型、独立的项目,命名空间的需求并不大,而且您永远不会为代码中的每个对象或概念创建命名空间。

使用库的大型项目受益于与这些库引入的名称隔离,以及一些内部组织以使可读性更容易。

同样,当创建一个库时,最好将其内容放入一个命名空间中,以免给您的用户带来麻烦和冲突(因为您不知道他们的项目有多大会是什么名字,他们可能想用什么名字)。

打个比方:如果您有三本书,您不必费心按字母顺序排列它们。但是,一旦你有一百个,你可能会决定把它们分类在你的书架上,以便于参考和心理健康。

而且,如果您现在从朋友那里再借 20 本书,您可能会将它们单独存放,以便在需要归还时更容易找到。

所以,在某种程度上,这是……你会知道为什么需要它,什么时候需要它。

【讨论】:

    【解决方案2】:

    “[Named] Namespaces”,顾名思义,是一种细分标识符空间的方法。除了解决文字冲突(“你有多个foo ...”)之外,它还使得在一个可能包含的大型成熟程序中find foo 变得相当容易数百甚至数千个模块。

    变量或例程的“名称”可能(?)暗示它是 什么,但可能不提供任何线索来说明它在 哪里,也不提供 context(不是一个技术术语)它所涉及的内容:“它只是成千上万的名字中的一个。”但是,如果您现在将它们分组到智能选择的命名空间中,您正在为它们添加一个有用的组织级别。在一个典型的“伟大的大项目”中,尤其是一个(也是典型的......)“你并不完全熟悉”的项目中,这种额外的面包屑水平是一个很大的好处。

    【讨论】:

      【解决方案3】:

      简单地说,命名空间允许在不同的上下文中使用相同的名称。

      假设您要创建两个函数,它们采用相同的参数并以两种不同的方式输出文本,为简单起见,您希望将它们都称为 print()

      由于它们都采用相同的参数,因此这里没有函数重载的机会,但是如果您将每个函数放在单独的命名空间中,然后调用print(),您可以通过调用简单地更改函数将执行的操作每次使用不同的命名空间。

      【讨论】:

      • 在该示例中,最好使用不同的、自记录的函数名称。
      • 是的,但是如果你的工作规模更大,并且你想在太大的函数集之间轻松切换,这个方法可能会派上用场,它是一个非常具体的例子,但它演示了一个您可以利用命名空间的方式来发挥自己的优势。
      【解决方案4】:

      如果我创建了一个包含 calculateStuff() 函数的库,而你也创建了一个包含 calculateStuff() 函数的库,那么想要同时使用我们两个库的其他人将会有一个不好的日。但是,如果我们都使用命名空间就没有问题,因为他/她可以区分myNamespace::calculateStuff()yourNamespace::calculateStuff()的功能,并且没有歧义。

      例如:std::shared_ptrboost::shared_ptr。如果没有命名空间,您将无法在同一个程序中同时使用这两者,因为名称 shared_ptr 会模棱两可。

      【讨论】:

      • 另一个经常出现的常见示例是标准 C++ 库中的 std::bind() 与 Winsock 库中的 ::bind()。没有命名空间,应该调用哪个bind()?编译器很难弄清楚这一点。使用适当的命名空间限定对 bind() 的调用解决了这个问题。