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

nak*_*iya 27 c++ namespaces

我以前从来没有为我的代码使用名称空间.(除了使用STL功能)

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

Ton*_*roy 22

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


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

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

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

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

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

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

  • 与命名空间,你可以定制提供非成员函数和模板:这是不可能的虚拟调度(和非成员函数对称操作符重载帮助-例如支持22 + my_type以及my_type + 22)

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

  • 虚拟调度通常涉及胖接口和笨拙的错误处理之间的妥协:使用命名空间可以选择简单地不在名称空间中提供无意义的功能,为编译时强制执行必要的客户端移植工作

  • 我在C++中没有和你一样多的经验,但这对我来说听起来相当邪恶.为什么不使用具有两个实现的接口?我看不到使用命名空间做任何优势.请原谅这条评论的可能天真:) (2认同)

Chu*_*dad 12

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

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

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


Pho*_*ong 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
Run Code Online (Sandbox Code Playgroud)

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

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