分享 C++命名空间的解释 2012-05-20 15:10:09

分类: C/C++

使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突。在C++中,变量、函数和类都是大量存在的。如果没有命名空间,这些变量、函数、类的名称将都存在于全局命名空间中,会导致很多冲突。比如,如果我们在自己的程序中定义了一个函数toupper(),这将重写标准库中的toupper()函数,这是因为这两个函数都是位于全局命名空间中的。命名冲突还会发生在一个程序中使用两个或者更多的第三方库的情况中。此时,很有可能,其中一个库中的名称和另外一个库中的名称是相同的,这样就冲突了。这种情况会经常发生在类的名称上。比如,我们在自己的程序中定义了一个Stack类,而我们程序中使用的某个库中也可能定义了一个同名的类,此时名称就冲突了。

Namespace 关键字的出现就是针对这种问题的。由于这种机制对于声明于其中的名称都进行了本地化,就使得相同的名称可以在不同的上下文中使用,而不会引起名称的冲突。或许命名空间最大的受益者就是C++中的标准库了。在命名空间出现之前,整个C++库都是定义在全局命名空间中的(这当然也是唯一的命名空间)。引入命名空间后,C++库就被定义到自己的名称空间中了,称之为std。这样就减少了名称冲突的可能性。我们也可以在自己的程序中创建自己的命名空间,这样可以对我们认为可能导致冲突的名称进行本地化。这点在我们创建类或者是函数库的时候是特别重要的。

命名空间基础

namespace 关键字使得我们可以通过创建作用范围来对全局命名空间进行分隔。本质上来讲,一个命名空间就定义了一个范围。定义命名空间的基本形式如下:

namespace 名称{//声明}

在命名空间中定义的任何东西都局限于该命名空间内。

下面就是一个命名空间的例子,其中对一个实现简单递减计数器的类进行了本地化。在该命名空间中定义了计数器类用来实现计数;其中的upperbound和lowerbound用来表示计数器的上界和下界。

演示命名空间

  1. namespace CounterNameSpace
  2. {
  3. int upperbound;
  4. int lowerbound;
  5. class counter
  6. {
  7. int count;
  8. public:
  9. counter(int n)
  10. {
  11. if ( n <= upperbound ){
  12. count = n;
  13. } else  {
  14. count = upperbound;
  15. }
  16. }
  17. void reset(int n)
  18. {
  19. if ( n < upperbound )
  20. {
  21. count = n;
  22. }
  23. }
  24. int run() {
  25. if ( count > lowerbound)
  26. {
  27. return count--;
  28. } else {
  29. return lowerbound;
  30. }
  31. }
  32. };
  33. }

其中的upperbound,lowerbound和类counter都是有命名空间CounterNameSpace定义范围的组成部分。

在命名空间中声明的标识符是可以被直接引用的,不需要任何的命名空间的修饰符。例如,在CounterNameSapce命名空间中,run()函数中就可以直接在语句中引用lowerbound:

点击(此处)折叠或打开

  1. if ( count > lowerbound)
  2. {
  3. return count--;
  4. }

然而,既然命名空间定义了一个范围,那么我们在命名空间之外就需要使用范围解析运算符来引用命名空间中的对象。例如,在命名空间CounterNameSpace定义的范围之外给upperbound赋值为10,就必须这样写:

CounterNameSpace::upperbound = 10;

或者在CounterNameSpace定义的范围之外想要声明一个counter类的对象就必须这样写:

CounterNameSpace::counter obj;

一般来讲,在命名空间之外想要访问命名空间内部的成员需要在成员前面加上命名空间和范围解析运算符。

下面的程序演示了如何使用CounterNameSpace这个命名空间:

演示命名空间

  1. #include <iostream>
  2. using namespace std;
  3. namespace CounterNameSpace
  4. {
  5. int upperbound;
  6. int lowerbound;
  7. class counter
  8. {
  9. int count;
  10. public:
  11. counter(int n)
  12. {
  13. if ( n <= upperbound )
  14. {
  15. count = n;
  16. } else
  17. {
  18. count = upperbound;
  19. }
  20. }
  21. void reset(int n)
  22. {
  23. if ( n < upperbound )
  24. {
  25. count = n;
  26. }
  27. }
  28. int run()
  29. {
  30. if ( count > lowerbound)
  31. {
  32. return count--;
  33. }
  34. else
  35. return lowerbound;
  36. }
  37. };
  38. }
  39. int main()
  40. {
  41. CounterNameSpace::upperbound = 100;
  42. CounterNameSpace::lowerbound = 0;
  43. CounterNameSpace::counter ob1(10);
  44. int i;
  45. do {
  46. i = ob1.run();
  47. cout << i << " ";
  48. } while (i > CounterNameSpace::lowerbound);
  49. cout << endl;
  50. CounterNameSpace::counter ob2(20);
  51. do {
  52. i = ob2.run();
  53. cout << i << " ";
  54. } while (i > CounterNameSpace::lowerbound);
  55. cout << endl;
  56. ob2.reset(100);
  57. do
  58. {  i = ob2.run();
  59. cout << i << " ";
  60. } while (i > CounterNameSpace::lowerbound);
  61. cout << endl;
  62. return 0;
  63. }

请注意:counter类以及upperbound和lowerbound的引用都是在前面加上了CounterNameSpace修饰符。但是,一旦声明了counter类型的对象,就没有必须在对该对象的任何成员使用这种修饰符了。因此ob1.run()是可以被直接调用的。其中的命名空间是可以被解析的。

相同的空间名称是可以被多次声明的,这种声明向相互补充的。这就使得命名空间可以被分割到几个文件中甚至是同一个文件的不同地方中。例如:

点击(此处)折叠或打开

  1. namespace NS
  2. {
  3. int i;
  4. }
  5. //...
  6. namespace NS
  7. {
  8. int j;
  9. }

其中命名空间NS被分割成两部分,但是两部分的内容却是位于同一命名空间中的。也就是NS。最后一点:命名空间是可以嵌套的。也就是说可以在一个命名空间内部声明另外的命名空间。

using关键字

如果在程序中需要多次引用某个命名空间的成员,那么按照之前的说法,我们每次都要使用范围解析符来指定该命名空间,这是一件很麻烦的事情。为了解决这个问题,人们引入了using关键字。using语句通常有两种使用方式:

using namespace 命名空间名称;

using 命名空间名称::成员;

第一种形式中的命名空间名称就是我们要访问的命名空间。该命名空间中的所有成员都会被引入到当前范围中。也就是说,他们都变成当前命名空间的一部分了,使用的时候不再需要使用范围限定符了。第二种形式只是让指定的命名空间中的指定成员在当前范围中变为可见。我们用前面的CounterNameSpace来举例,下面的using语句和赋值语句都是有效的:

using CounterNameSpace::lowerbound; //只有lowerbound当前是可见的

lowerbound = 10; //这样写是合法的,因为lowerbound成员当前是可见的

using CounterNameSpace; //所有CounterNameSpace空间的成员当前都是可见的

upperbound = 100; //这样写是合法的,因为所有的CounterNameSpace成员目前都是可见的

下面是我们对之前的程序进行修改的结果:

使用using

  1. #include <iostream>
  2. using namespace std;
  3. namespace CounterNameSpace
  4. {
  5. int upperbound;
  6. int lowerbound;
  7. class counter
  8. {
  9. int count;
  10. public:
  11. counter(int n)
  12. {
  13. if ( n < upperbound)
  14. {
  15. count = n;
  16. }
  17. else
  18. {
  19. count = upperbound;
  20. }
  21. }
  22. void reset( int n )
  23. {
  24. if ( n <= upperbound )
  25. {
  26. count = n;
  27. }
  28. }
  29. int run()
  30. {
  31. if ( count > lowerbound )
  32. {
  33. return count--;
  34. }
  1. else
  2. {
  3. return lowerbound;
  4. }
  5. }
  6. };
  7. }
  8. int main()
  9. {
  10. //这里只是用CounterNameSpace中的upperbound
  11. using CounterNameSpace::upperbound;
  12. //此时对upperbound的访问就不需要使用范围限定符了
  13. upperbound = 100;
  14. //但是使用lowerbound的时候,还是需要使用范围限定符的
  15. CounterNameSpace::lowerbound = 0;
  16. CounterNameSpace::counter ob1(10);
  17. int i;
  18. do
  19. {
  20. i = ob1.run();
  21. cout << i << " ";
  22. }while( i > CounterNameSpace::lowerbound);
  23. cout << endl;
  24. //下面我们将使用整个CounterNameSpace的命名空间
  25. using namespace CounterNameSpace;
  26. counter ob2(20);
  27. do
  28. {
  29. i = ob2.run();
  30. cout << i << " ";
  31. }while( i > CounterNameSpace::lowerbound);
  32. cout << endl;
  33. ob2.reset(100);
  34. lowerbound = 90;
  35. do
  36. {
  37. i = ob2.run();
  38. cout << i << " ";
  39. }while( i > lowerbound);
  40. return 0;
  41. }
  42. 上面的程序还为我们演示了重要的一点:当我们用using引入一个命名空间的时候,如果之前有引用过别的命名空间(或者同一个命名空间),则不会覆盖掉对之前的引入,而是对之前引入内容的补充。也就是说,到最后,上述程序中的std和CounterNameSpace这两个命名空间都变成全局空间了。
  43. 没有名称的命名空间
  44. 有一种特殊的命名空间,叫做未命名的命名空间。这种没有名称的命名空间使得我们可以创建在一个文件范围里可用的命名空间。其一般形式如下:
  45. namespace
  46. {
  47. //声明
  48. }

我们可以使用这种没有名称的命名空间创建只有在声明他的文件中才可见的标识符。也即是说,只有在声明这个命名空间的文件中,它的成员才是可见的,它的成员才是可以被直接使用的,不需要命名空间名称来修饰。对于其他文件,该命名空间是不可见的。我们在前面曾经提到过,把全局名称的作用域限制在声明他的文件的一种方式就是把它声明为静态的。尽管C++是支持静态全局声明的,但是更好的方式就是使用这里的未命名的命名空间。

std命名空间

标准C++把自己的整个库定义在std命名空间中。这就是本书的大部分程序都有下面代码的原因:

using namespace std;

这样写是为了把std命名空间的成员都引入到当前的命名空间中,以便我们可以直接使用其中的函数和类,而不用每次都写上std::。

当然,我们是可以显示地在每次使用其中成员的时候都指定std::,只要我们喜欢。例如,我们可以显示地采用如下语句指定cout:

std::cout << “显示使用std::来指定cout”;

如果我们的程序中只是少量地使用了 std 命名空间中的成员,或者是引入 std 命名空间可能导致命名空间的冲突的话,我们就没有必要使用 using namespace std; 了。然而,如果在程序中我们要多次使用 std 命名空间的成员,则采用 using namespace std; 的方式把 std 命名空间的成员都引入到当前命名空间中会显得方便很多,而不用每次都单独在使用的时候显示指定
转载地址:http://blog.renren.com/share/730973714/7874424429

分享 C++命名空间的解释相关推荐

  1. Spring配置文件头部约束和命名空间配置解释

    比如一个标准的beans.xml文件如下所示: <?xml version="1.0" encoding="UTF-8"?> <beans x ...

  2. 「千言万语」系列技术分享:迈向可解释的自然语言处理

    神经网络模型已经成功应用于大量自然语言处理任务.当今主流的端到端深度学习模型都是黑盒模型,人们难以知道模型做出某一决策的依据,从而不敢轻易放心地使用.同时,开发人员也很难进行针对性的调整(比如修改网络 ...

  3. Python分享:命名空间和作用域的基础知识整合

    什么是命名空间? 命名空间是一个系统,它对Python中的每个对象都有一个唯一的名称.对象可能是变量或方法. Python本身以Python字典的形式维护名称空间. 在类似的行中,Python解释器可 ...

  4. 播放失败246106异常代码_美的燃气热水器修理分享(附代码解释)

    上门检修一台美的强排热水器. 试机检查:打开水流,强排风机虽转,未听到燃气电磁阀吸合和燃气火力声音,出水口也只有冷水流出,几秒后显示E2.查相应的代码解释E2:风压异常或风机故障.但观风机运行速度声音 ...

  5. 【无私分享:ASP.NET CORE 项目实战】目录索引

    简介 首先,我们的  [无私分享:从入门到精通ASP.NET MVC]   系列已经接近尾声,希望大家在这个过程中学到了一些思路和方法,而不仅仅是源码. 因为是第一次写博客,我感觉还是比较混乱的,其中 ...

  6. php 命名空间地址,php命名空间简介

    为什么使用命名空间,随着项目的文件增多,就不可避免的出现类名,函数名,常量名重复的现象,本文主要和大家分享php命名空间简介,希望能帮助到大家.未定义命名空间的如下图 Fatal error: Can ...

  7. 论NLP可解释的评估:什么才是“好”的解释?

    ©PaperWeekly 原创 · 作者|李泺秋 学校|浙江大学硕士生 研究方向|自然语言处理.知识图谱 前言 深度学习模型已经成为 NLP 的标准工具,在解决许多问题上大显神通.然而其黑盒性质也成为 ...

  8. 语言条件语序心得_考研分享 | 王远新语言学教程要点总结(第五章)

    点击上方蓝字,关注我吧作者|雨   轩编辑|武思文上次小编分享了王远新老师<语言学教程>的第四章:考研分享 | 王远新<语言学教程>要点总结(第四章),今天小编为大家带来的是第 ...

  9. JavaScript 编程精解 中文第三版 二十一、项目:技能分享网站

    二十一.项目:技能分享网站 原文:Project: Skill-Sharing Website 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 部分参考了<JavaScri ...

最新文章

  1. [C#][EF] 添加表添加不进来
  2. html5控件组合,[Vue 3] 教程 – 可复用与组合 – 插件
  3. 数据结构 归并排序 C++
  4. XenApp_XenDesktop_7.6实战篇之九:SQL Server数据库服务器规划及部署
  5. 从C语言的角度重构数据结构系列(五)-C语言的程序结构和基本语法
  6. Aeroplane chess HDU - 4405(期望dp)
  7. liskov替换原则_坚实原则:Liskov替代原则
  8. RUNOOB python练习题33 使用join方法实现用逗号分隔列表
  9. Leetcode--78. 子集
  10. Adobe Illustrator的教程等距购物移动应用程序
  11. GitHub:围剿Python计划!程序员:早知必有一战!你站谁?
  12. css标签权重计算知识详解
  13. python 3des加密_python3使用3des加密
  14. 怎样理解封装,继承,多态!三者的区别?
  15. 使用Go清理数据:第1部分
  16. 测量误差(error)的概念
  17. 论文翻译:2021_Acoustic Echo Cancellation with Cross-Domain Learning
  18. vue 中 mixins 的使用
  19. 手机九宫格滑动解锁方法种数(389112种)
  20. 葛洛夫、盖兹、施振荣、张忠谋、Michael Dell的30岁

热门文章

  1. 【转】Luajit-2.1.0-beta1的发布和生成arm64用bytecode的解脱
  2. U3D 打包时找不到tag的问题
  3. 转 无障碍阅读 role aria-*
  4. 确保字符串的每个单词首字母都大写,其余部分小写
  5. Linux下进度条小程序
  6. sqlplus: error while loading shared libraries
  7. Microsoft SQL server 2000 安装挂起 mssql 2000 挂起无法安装的问题
  8. VMware安装Linux ubuntu虚拟机
  9. 手把手教你webpack4.x从零开始搭建vue项目
  10. 第二次学习笔记(linux/unix操作系统)