Ton*_*roy 22
经常被忽视的一个原因是,只需通过更改单行代码来选择一个名称空间而不是另一个名称空间,就可以选择另一组函数/变量/类型/常量 - 例如协议的另一个版本,或单线程与多线程 - 线程支持,平台X或Y的OS支持 - 编译和运行.通过包含具有不同声明的标头或使用#defines和可以实现相同类型的效果#ifdefs,但这粗略地影响整个翻译单元,如果链接不同的版本,你可以得到未定义的行为.使用命名空间,您可以通过使用仅在活动命名空间中应用的命名空间进行选择,或者通过命名空间别名进行选择,以便它们仅适用于使用该别名的位置,但它们实际上已解析为不同的链接符号,因此可以在不使用的情况下进行组合未定义的行为.这可以以类似于模板策略的方式使用,但影响更隐式,自动和普遍 - 一种非常强大的语言功能.
更新:解决marcv81的评论......
为什么不使用具有两个实现的接口?
"接口+实现"在概念上是选择上面的别名命名空间正在做什么,但如果你的意思是特定的运行时多态性和虚拟调度:
生成的库或可执行文件不需要包含所有实现,并且在运行时不断地直接调用所选实现的实现
作为一个实现的结合,编译器可以使用无数的优化,包括内联,死代码消除,以及"实现"之间不同的常量可以用于例如数组的大小 - 允许自动内存分配而不是更慢的动态分配
不同的命名空间必须支持相同的使用语义,但不一定支持完全相同的函数签名集,就像虚拟调度的情况一样
与命名空间,你可以定制提供非成员函数和模板:这是不可能的虚拟调度(和非成员函数对称操作符重载帮助-例如支持22 + my_type以及my_type + 22)
不同的命名空间可以指定用于某些目的的不同类型(例如,散列函数可能在一个命名空间中返回32位值,但在另一个命名空间中返回64位值),但虚拟接口需要具有统一静态类型,这意味着笨拙和高开销间接相似boost::any或boost::variant最坏情况选择,其中高阶位有时是无意义的
虚拟调度通常涉及胖接口和笨拙的错误处理之间的妥协:使用命名空间可以选择简单地不在名称空间中提供无意义的功能,为编译时强制执行必要的客户端移植工作
它可以帮助您更好地理解.
例如:
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中轻松记录命名空间实体)