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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4211827/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:51:32  来源:igfitidea点击:

Why and how should I use namespaces in C++?

c++namespaces

提问by nakiya

I have never used namespaces for my code before. (Other than for using STL functions)

我以前从未为我的代码使用过命名空间。(除了使用 STL 函数)

  1. Other than for avoiding name conflicts, is there any other reason to use namespaces?
  2. Do I have to enclose both declarations and definitions in namespace scope?
  1. 除了避免名称冲突之外,还有其他使用名称空间的原因吗?
  2. 我是否必须在命名空间范围内包含声明和定义?

采纳答案by Chubsdad

Hereis a good reason (apart from the obvious stated by you).

是一个很好的理由(除了你说的显而易见的)。

Since namespace can be discontiguous and spread across translation units, they can also be used to separate interface from implementation details.

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

Definitions of names in a namespace can be provided either in the same namespace or in any of the enclosing namespaces (with fully qualified names).

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

回答by Tony Delroy

One reason that's often overlooked is that simply by changing a single line of code to select one namespaces over another you can select an alternative set of functions/variables/types/constants - such as another version of a protocol, or single-threaded versus multi-threaded support, OS support for platform X or Y - compile and run. The same kind of effect might be achieved by including a header with different declarations, or with #definesand #ifdefs, but that crudely affects the entire translation unit and if linking different versions you can get undefined behaviour. With namespaces, you can make selections via using namespace that only apply within the active namespace, or do so via a namespace alias so they only apply where that alias is used, but they're actually resolved to distinct linker symbols so can be combined without undefined behaviour. This can be used in a way similar to template policies, but the affect is more implicit, automatic and pervasive - a very powerful language feature.

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



UPDATE: addressing marcv81's comment...

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

Why not use an interface with two implementations?

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

"interface + implementations" is conceptually what choosing a namespace to alias above is doing, but if you mean specifically runtimepolymorphism and virtual dispatch:

“接口 + 实现”在概念上是为上面的别名选择命名空间正在做的事情,但如果您特别指的是运行时多态性和虚拟分派:

  • the resultant library or executable doesn't need to contain all implementations and constantly direct calls to the selected one at runtime

  • as one implementation's incorporated the compiler can use myriad optimisations including inlining, dead code elimination, and constants differing between the "implementations" can be used for e.g. sizes of arrays - allowing automatic memory allocation instead of slower dynamic allocation

  • different namespaces have to support the same semantics of usage, but aren't bound to support the exact same set of function signatures as is the case for virtual dispatch

  • with namespaces you can supply custom non-member functions and templates: that's impossible with virtual dispatch (and non-member functions help with symmetric operator overloading - e.g. supporting 22 + my_typeas well as my_type + 22)

  • different namespaces can specify different types to be used for certain purposes (e.g. a hash function might return a 32 bit value in one namespace, but a 64 bit value in another), but a virtual interface needs to have unifying static types, which means clumsy and high-overhead indirection like boost::anyor boost::variantor a worst case selection where high-order bits are sometimes meaningless

  • virtual dispatch often involves compromises between fat interfaces and clumsy error handling: with namespaces there's the optionto simply not provide functionality in namespaces where it makes no sense, giving a compile-time enforcement of necessary client porting effort

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

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

  • 不同的命名空间必须支持相同的使用语义,但不一定支持与虚拟分派的情况完全相同的函数签名集

  • 使用命名空间,您可以提供自定义的非成员函数和模板:虚拟分派是不可能的(并且非成员函数有助于对称运算符重载 - 例如支持22 + my_type以及my_type + 22

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

  • 虚拟调度通常涉及胖接口和笨拙错误处理之间的折衷:对于命名空间,可以选择在没有意义的命名空间中简单地不提供功能,从而在编译时强制执行必要的客户端移植工作

回答by Phong

It can help you for a better comprehension.

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

eg:

例如:

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

You can also think of it as module in your system.

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

It can also be usefull for an writing documentation (eg: you can easily document namespace entity in doxygen)

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

回答by Ken D

You can think of namespaces as logical separated units for your application, and logical here means that suppose we have two different classes, putting these two classes each in a file, but when you notice that these classes share something enough to be categorized under one category, that's one strong reason to use namespaces.

您可以将命名空间视为应用程序的逻辑分隔单元,这里的逻辑意味着假设我们有两个不同的类,将这两个类分别放在一个文件中,但是当您注意到这些类共享的东西足以归为一个类别时,这是使用命名空间的一个重要原因。

回答by Fred Nurk

  1. Aren't name collisions enough of a reason? ADL subtleties, especially with operator overloads, are another.

  2. That's the easiest way. You can also prefix names with the namespace, e.g. my_namespace::name, when defining.

  1. 名称冲突还不够理由吗?ADL 的微妙之处,尤其是运算符重载,则是另一个问题。

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

回答by wheaties

  1. Answer: If you ever want to overload the new, placement new, or delete functions you're going to want to do them in a namespace. No one wants to be forced to use your version of new if they don't require the things you require.
  2. Yes
  1. 答:如果您想重载 new、placement new 或 delete 函数,您将希望在命名空间中执行它们。如果他们不需要您需要的东西,没有人愿意被迫使用您的 new 版本。
  2. 是的