为了防止命名冲突。命名空间分割了全局作用域,每个命名空间就是一个作用域。命名空间可以嵌套。

  1. namespace fuckspace{ // 如果在这之前没有fuckspace命名空间,则是定义
  2. // 如果已经存在,则是为命名空间增加成员
  3. // 在当前作用域内名字必须唯一,不同作用域可以一样。
  4. // 可以在全局作用域,可以嵌套,不能在类、函数内部。
  5. class Fucker1{/* ... */};
  6. class Fucker2{/* ... */};
  7. } //这里不需要分号
  8. fuckspace::Fucker1 shit = fuckspace::Fucker1();
  9. // 假设有一个类Fucker,要定义在fuckspace空间中。文件为:Fucker.h、Fucker.cpp、main.cpp
  10. /******************Fucker.h**********************/
  11. namespace fuckspace{
  12. class Fucker{ // 定义类
  13. void func(); // 声明成员
  14. }
  15. }
  16. /******************Fucker.cpp**********************/
  17. #include "Fucker.h" // 注意!!不要把include放在命名空间内部。
  18. namespace fuckspace{
  19. void Fucker::func(){} // 定义成员
  20. }
  21. void fuckspace::Fucker::func(){} //同上
  22. /******************main.cpp**********************/
  23. #include "Fucker.h"
  24. int main(){
  25. using fuckspace::Fucker;
  26. Fucker fucker;
  27. return 0;
  28. }
  29. // *****************************************************************************
  30. // 模板特例化必须定义在原始模板所在的命名空间中。
  31. namespace std{
  32. template<>
  33. class hash<Sales_data>; // 必须声明在原始模板空间中。
  34. }
  35. template<>
  36. class std::hash<Sales_data>{
  37. }
  38. // *****************************************************************************
  39. // 嵌套命名空间
  40. namespace A {
  41. namespace B {
  42. class Fuck {}
  43. }
  44. namespace C {
  45. class Shit();
  46. }
  47. }
  48. // 外部访问C
  49. A::C::Shit shit;
  50. // *****************************************************************************
  51. // 全局命名空间:在全局作用域定义的命名空间。
  52. // 全局作用域:在所有类、函数、命名空间之外的作用域。
  53. namespace A {
  54. }
  55. ::A // 访问全局作用域中的A

内联命名空间

C++新标准,内联命名空间中的名字可以被外层的命名空间直接访问。

  1. // ***************************************************************************
  2. // FifthEd.h
  3. // 显式内联,inline必须出现在第一次定义namespace的地方。
  4. inline namespace FifthEd { } // 《C++ Primer》第5版的代码
  5. namespace FifthEd { // 前面已经inline了,这里不用再写,默认就是inline
  6. class Fuck { /* .. . */};
  7. }
  8. // ***************************************************************************
  9. // FourthEd.h
  10. namespace FourthEd {
  11. class Fuck { /* .. . */}; // 第四版的代码
  12. }
  13. // ***************************************************************************
  14. /// cpp_primer.h
  15. namespace CPP_Primer {
  16. #include "FifthEd.h"
  17. #include "FourthEd.h"
  18. }
  19. CPP_Primer::FifthEd::Fuck // 调用第四版的代码
  20. CPP_Primer::Fuck // 调用最新版的代码(第五版)

未命名空间

  1. namespace { // 未命名空间,
  2. int fuck1; // 里面声明的变量都拥有静态生命周期
  3. int fuck2;
  4. }

同一个文件内的未命名空间可以不连续,但是在不同文件互相是完全不相关的。
如果一个头文件定义了未命名空间,则该命名空间中定义的名字将在每个包含了该头文件的文件中对应不同实体。
可以用未命名空间代替static来声明定义静态变量,static是C的设计。

  1. /******************fucker.h*********************/
  2. int i_global; // 这和下面的i_global定义等价,所以不能同时出现。
  3. namespace { // 未命名空间,里面的变得
  4. int i_global; // 全局变量,冲突
  5. string str_global; // 全局变量
  6. }
  7. ...... // 文件内其他代码
  8. namespace { // 在同一个文件内,可以不连续。
  9. char ch_global; // 全局变量
  10. double d_global; // 全局变量
  11. }
  12. // 在fucker1.h中include了fucker.h
  13. // 在fucker2.h中include了fucker.h
  14. // fucker1和fucker2中的i_global是两个独立的全局变量。
  15. namespace local {
  16. namespace {
  17. int i_global;
  18. }
  19. }
  20. // 正确:定义在嵌套的未命名的命名空间中的i与全局作用域中的i不同
  21. local::i_global = 42;

使用命名空间成员

  1. // ******************************************************************************
  2. // 命名空间别名
  3. namespace fucker{ }
  4. namespace fuckerback = fucker; // 命名空间别名
  5. namespace fuckoff = fucker::bitch:son; // 嵌套的也行。
  6. // ******************************************************************************
  7. // using声明
  8. void fuck(){
  9. using fucker::bitch:son; // using声明,在fuck内引入son成员
  10. ......; // 可直接访问son成员。
  11. return; // 作用域结束,using声明失效
  12. }
  13. // ******************************************************************************
  14. // using指示(情况远比using声明复杂)
  15. // 将命名空间成员提升到包含命名空间本身和using指示的最近作用域
  16. using namespace std; // using指示
  17. namespace A { // 全局作用域
  18. int i, j;
  19. }
  20. void f(){ // 全局作用域
  21. using namespace A; // 把A中的名字注入到全局作用域中
  22. cout << i * j << endl;
  23. }
  24. namespace blip{
  25. int i = 16, j = 15, k = 23;
  26. // 其他声明
  27. }
  28. int j = 0; // 正确:blip的j隐藏在命名空间中
  29. void manip()
  30. {
  31. //using指示,blip中的名字被“添加”到全局作用域中
  32. using namespace blip; // 如果使用了j则将在::j和blip::j之间产生冲突
  33. ++i; // 将blip::i设定为17
  34. ++j; // 二义性错误:是全局的J还是blip::j?
  35. ++::j; // 正确:将全局的j设定为1
  36. ++blip::j; // 正确:将blip::j设定为16
  37. int k=97; // 当前局部的K隐藏了blip::k
  38. ++k; // 将当前局部的k设定为98
  39. }

头文件如果在其顶层作用域中含有using指示或using声明,则会将名字注入到所有包含了该头文件的文件中。这很不可取,最多在函数、命名空间内使用。
综上我们应该尽量少使用using指示,可以命名空间本身的实现文件中使用。

  1. // ************************************************************************
  2. // test.h
  3. #ifndef _TEST_H_
  4. #define _TEST_H_
  5. using namespace std; // using指示,很不可取,所有包含test.h的文件中都将注入std的所有名字!
  6. // 很容易产生冲突。
  7. using std::cout; // using声明,很不可取,理由同上,很容易冲突。
  8. class test {
  9. ......
  10. };
  11. #endif
  12. // ************************************************************************
  13. // test.cpp
  14. #include "test.h"
  15. using namespace std; // using指示,在源文件中就可以。但更好的选择是using声明。
  16. using std::cout; // using声明,最规范的写法,
  17. using std::endl; // 很清楚的知道当前文件使用了std中的哪些名字
  18. void test::fuck(){
  19. using std::cout; // 局部作用域using声明,没毛病。
  20. cout << "......" << std::endl;
  21. }