命名空间就是为类型、函数、变量提供一个作用域限制。

1 命名空间的定义

注意:定义命令空间时,结束时不要加分号
namespace 命名空间名字 {
  ...
}

2 命名空间的使用

由于使用命名空间后,变量的作用域被限定,所以在使用变量时,就需要通过特定方式来完成。需要用到 :: 域解析操作符

  1. 暴露整个命名空间中的变量 using namespace name;
  2. 暴露命名空间中的某个变量 using name::variable;
  3. 使用指定变量 name::variable
  4. 直接使用 ::全局变量,使用::前缀来访问一个变量或函数指的是对全局命名空间的访问。全局命名空间是最外层的命名空间,它包含所有不属于任何其他命名空间的变量、函数、类型等。

3 用法总结

3.1 :: 全局变量

该项目test01目录在 /assets/CPlusPlus/01_namespace/test01_02/

使用::前缀来访问一个变量或函数指的是对全局命名空间的访问。全局命名空间是最外层的命名空间,它包含所有不属于任何其他命名空间的变量、函数、类型等。

这部分内容通过 ns.hns.cppmain.cpp三个文件编写证明。

3.2 inline内联命令空间

该项目test02目录在 /assets/CPlusPlus/01_namespace/test01_02/

C++11 标准中引入了一种新的嵌套命名空间,称为内联命名空间(inline namespace)。和普通的嵌套命名空间不同,内联命名空间中的名字可以被外层命名空间直接使用。也就是说,我们无须在内联命名空间的名字前添加表示该命名空间的前缀,通过外层命名空间的名字就可以直接访问它。

定义内联命名空间的方式是在关键字 namespace 前添加关键字 inline。

优点:实际上,该特性可以帮助库作者无缝升级库代码,让客户不用修改任何代码也能够自由选择新老库代码。

3.3 多文件命名空间合并

不同头文件中也可以使用名称相同的命名空间(也就是说,分散在不同头文件中的同名命名空间会合并为一个),但前提是位于该命名空间中的成员必须保证互不相同。

该项目目录在 /assets/CPlusPlus/01_namespace/test03/

3.4 头文件全局变量多定义

比如有三个文件,h1.hh2.hmain.cpp。其中:

/* filename: h1.h */
namespace demo {
  int a = 100;
}

/* filename: h2.h */
namespace demo {
  int b = 200;
}

/* filename: main.cpp */
#include "h1.h"
#include "h2.h"

int
main (int argc, char *argv[]) {

  std::cout << demo::a << std::endl;
  std::cout << demo::b << std::endl;

  return 0;
}

为什么以上内容编译没有问题呢?

答:因为只有 main.cpp 这一个源文件包含了进行了全局变量a和b的初始化。如果还有h1.cpp或者h2.cpp,并且包含各自的头文件,则会出现多重定义的问题。

3.4.1 关于多个头文件都有相同的命名空间

我们可以参考 geos 库(OpenCV其实也一样)的实现,进行简要的分析:

  1. 整个库就是 geos,所以所有的变量定义,都是在 namespace geos中,然后再根据每层的功能,分各自的命名空间和变量。

    alt text

  2. 比如有个:geom 部分,所以 namespace geos 中嵌套了 namespace geom

    alt text

参考

参考1:C++20标准下的嵌套命名空间和内联命名空间

参考2:C++命名空间在多文件编程中的具体用法

参考3:C++小知识-名字空间的声明、定义与合并