为什么以及如何在C ++中使用命名空间?

时间:2010-11-18 05:02:12

标签: c++ namespaces

我以前从未在代码中使用过命名空间。 (除了使用STL功能外)

  1. 除了避免名称冲突外,还有其他原因要使用命名空间吗?
  2. 我是否必须在命名空间范围内附上声明和定义?

6 个答案:

答案 0 :(得分:22)

经常被忽视的一个原因是,只需通过更改单行代码来选择一个名称空间而不是另一个名称空间,就可以选择另一组函数/变量/类型/常量 - 例如另一个版本的协议,或单个 - 线程与多线程支持,平台X或Y的OS支持 - 编译和运行。通过包含具有不同声明的标头或#defines#ifdefs可以实现相同类型的效果,但这会粗略地影响整个翻译单元,如果链接不同的版本,则可以获得未定义的行为。使用命名空间,您可以通过使用仅在活动命名空间中应用的命名空间进行选择,或者通过命名空间别名进行选择,以便它们仅适用于使用该别名的位置,但它们实际上已解析为不同的链接符号,因此可以在不使用的情况下进行组合未定义的行为。这可以以类似于模板策略的方式使用,但影响更隐蔽,自动且普遍 - 一种非常强大的语言功能。


更新:解决marcv81的评论......

  

为什么不使用具有两种实现的接口?

“接口+实现”在概念上是选择上面的别名命名空间正在做什么,但如果你的意思是运行时多态和虚拟调度:

  • 生成的库或可执行文件不需要包含所有实现,并且在运行时不断地直接调用所选实现

  • 作为一个实现的结合,编译器可以使用无数的优化,包括内联,死代码消除,以及“实现”之间不同的常量可以用于例如数组的大小 - 允许自动内存分配而不是较慢的动态分配

  • 不同的命名空间必须支持相同的使用语义,但不一定支持完全相同的函数签名集,就像虚拟调度的情况一样

    < / LI>
  • 使用命名空间,您可以提供自定义非成员函数和模板:虚拟调度是不可能的(非成员函数有助于对称运算符重载 - 例如支持22 + my_type以及{{1} })

  • 不同的命名空间可以指定用于某些目的的不同类型(例如,散列函数可能在一个命名空间中返回32位值,而在另一个命名空间中返回64位值),但虚拟接口需要统一静态类型,这意味着笨拙和高开销间接,如my_type + 22boost::any或最坏情况选择,其中高阶位有时无意义

  • 虚拟调度通常涉及胖接口和笨拙的错误处理之间的妥协:对于命名空间,选项根本不提供命名空间中的功能,这是没有意义的,给出了编译时执行必要的客户端移植工作

答案 1 :(得分:12)

Here是一个很好的理由(除了你明显的说法)。

由于命名空间可能不连续并且可以跨翻译单元传播,因此它们也可用于将接口与实现细节分开。

名称空间中名称的定义可以在同一名称空间中提供,也可以在任何封闭名称空间中提供(具有完全限定名称)。

答案 2 :(得分:5)

它可以帮助您更好地理解。

例如:

std::func <- all function/class from C++ standard library
lib1::func <- all function/class from specific library
module1::func <-- all function/class for a module of your system

您还可以将其视为系统中的模块。

它对于编写文档也很有用(例如:你可以在doxygen中轻松记录命名空间实体)

答案 3 :(得分:2)

  1. 名称冲突是否足够原因? ADL的微妙之处,特别是运算符过载,是另一个。

  2. 这是最简单的方法。您还可以使用命名空间为名称添加前缀,例如my_namespace :: name,定义时。

答案 4 :(得分:2)

您可以将命名空间视为应用程序的逻辑分隔单元,这里的逻辑意味着假设我们有两个不同的类,将这两个类分别放在一个文件中,但是当您注意到这些类共享足够的内容以进行分类时在一个类别下,这是使用命名空间的一个强有力的理由。

答案 5 :(得分:1)

  1. 答案:如果您想要重载新的,放置新的或删除函数,那么您将要在命名空间中执行它们。如果他们不需要你需要的东西,没有人愿意被迫使用你的新版本。