使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突。在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:

点击(此处)折叠或打开

然而,既然命名空间定义了一个范围,那么我们在命名空间之外就需要使用范围解析运算符来引用命名空间中的对象。例如,在命名空间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()是可以被直接调用的。其中的命名空间是可以被解析的。

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

点击(此处)折叠或打开

其中命名空间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++ 命名空间Namespace 的解析的更多相关文章

  1. PHP 命名空间(namespace)

    PHP 命名空间(namespace) PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物. 不过在PHP当中还是有着相当重要的意义 ...

  2. PHP命名空间(Namespace)的使用详解(转)

    对于命名空间,官方文档已经说得很详细[查看],我在这里做了一下实践和总结. 命名空间一个最明确的目的就是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误.这种情况下只 ...

  3. PHP命名空间(Namespace)的使用详解

    对于命名空间,官方文档已经说得很详细[查看],我在这里做了一下实践和总结. 命名空间一个最明确的目的就是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误.这种情况下只 ...

  4. PHP深入浅出之命名空间(Namespace)的使用详解

    对于命名空间,官方文档已经说得很详细[查看],我在这里做了一下实践和总结. 命名空间一个最明确的目的就是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误.这种情况下只 ...

  5. PHP的命名空间namespace

    对于命名空间,官方文档已经说得很详细[查看],我在这里做了一下实践和总结. 命名空间一个最明确的目的就是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误.这种情况下只 ...

  6. XAML实例教程系列 - 命名空间(NameSpace) 三

    XAML实例教程系列 - 命名空间(NameSpace) 2012-05-28 14:14 by jv9, 2205 阅读, 10 评论, 收藏, 编辑 上一篇曾提及XAML中,每个对象元素的声明是对 ...

  7. PHP 命名空间(namespace)定义

    PHP 命名空间(namespace) PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物. 不过在PHP当中还是有着相当重要的意义 ...

  8. Atitit  深入理解命名空间namespace  java c# php js

    Atitit  深入理解命名空间namespace  java c# php js 1.1. Namespace还是package1 1.2. import同时解决了令人头疼的include1 1.3 ...

  9. PHP 使用命名空间(namespace),实现自动加载

    示例: #/DB/MySql.class.php也就是DB文件夹下有MySql.class.php文件 namespace DB; class MySql { public function __co ...

随机推荐

  1. appium安装,和遇到的问题

    https://www.cnblogs.com/fnng/p/4540731.html Appium环境搭建时在cmd中输入appium-doctor命令,提示’appium-doctor’ 不是内部 ...

  2. python基础补漏-09-反射

    isinstance class A: passclass B(A): pass b = B()print isinatance(b,A)issubclass 判断某一个类是不是另外一个类的派生类 # ...

  3. [git 学习篇] 创建公钥

    http://riny.net/2014/git-ssh-key/ 1 安装 windows gitbash    msysgit是Windows版的Git,从https://git-for-wind ...

  4. POJ 1315 Don't Get Rooked

    Don't Get Rooked Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 2086   Accepted: 1325 ...

  5. C# 时间与时间戳互转 13位|13位時間戳与日期换转

    这里直接上代码 懂C# 的程序猿 一看便知道如何使用的... /// <summary> /// 将Unix时间戳转换为DateTime类型时间 /// </summary> ...

  6. HDU——2087剪花布条

    剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  7. ACM程序设计选修课——Problem D: (ds:树)合并果子(最优二叉树赫夫曼算法)

    Problem D: (ds:树)合并果子 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 80  Solved: 4 [Submit][Status][ ...

  8. BZOJ-3040 最短路

    最短路+堆优化. 普通的堆还不行,自己用的是配对堆(貌似斐波那契堆也行?毕竟理论复杂度) 然后发现自己的配对堆比云神的不知快了多少...我照着他的模版打的喂.. 然后发现前T条边不理都能A... 数据 ...

  9. hdu 2888 二维RMQ

    Check Corners Time Limit: 2000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  10. 树上的路径 BZOJ 3784

    树上的路径 [问题描述] 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a<b.将这n*(n-1)/2个距 ...