C++命名空间详解

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

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

命名空间基础

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

  namespace 名称{//声明}

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

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

 ///演示命名空间 1 namespace CounterNameSpace
 2 {
 3
 4     int upperbound;
 5     int lowerbound;
 6
 7     class counter
 8     {
 9
10         int count;
11    public:
12      counter(int n)
13      {
14
15             if ( n <= upperbound ){
16                 count = n;
17             } else  {
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       if ( count > lowerbound)
30        {
31                 return count--;
32        } else {
33                 return lowerbound;
34        }
35       }
36     };
37 }

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

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

1 ///在命名空间中使用变量
2 if ( count > lowerbound)
3 {
4     return count--;
5 }

  然而,既然命名空间定义了一个范围,那么我们在命名空间之外就需要使用范围解析运算符来引用命名空间中的对象。例如,在命名空间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
 8 class counter
 9 {
10     int count;
11 public:
12     counter(int n)
13     {
14         if ( n <= upperbound )
15         {
16             count = n;
17         }
18         else
19         {
20             count = upperbound;
21         }
22     }
23     void reset(int n)
24     {
25         if ( n < upperbound )
26         {
27             count = n;
28         }
29     }
30     int run()
31     {
32         if ( count > lowerbound)
33         {
34             return count--;
35         }
36         else
37             return lowerbound;
38     }
39 };
40 }
41
42 int main()
43 {
44     CounterNameSpace::upperbound = 100;
45     CounterNameSpace::lowerbound = 0;
46     CounterNameSpace::counter ob1(10);
47     int i;
48     do
49     {
50         i = ob1.run();
51         cout << i << " ";
52     }
53     while (i > CounterNameSpace::lowerbound);
54     cout << endl;
55     CounterNameSpace::counter ob2(20);
56     do
57     {
58         i = ob2.run();
59         cout << i << " ";
60     }
61     while (i > CounterNameSpace::lowerbound);
62
63     cout << endl;
64     ob2.reset(100);
65     do
66     {
67         i = ob2.run();
68         cout << i << " ";
69
70     }
71     while (i > CounterNameSpace::lowerbound);
72     cout << endl;
73     return 0;
74 }

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

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

 1 namespace NS
 2
 3 {
 4
 5 int i;
 6
 7 }
 8
 9
10
11 //...
12
13
14 namespace NS
15
16 {
17
18     int j;
19
20 }

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

using关键字

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

  using namespace 命名空间名称;

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

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

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

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

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

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

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

  1 ///使用using
  2
  3 #include <iostream>
  4
  5 using namespace std;
  6
  7 namespace CounterNameSpace
  8
  9 {
 10
 11     int upperbound;
 12
 13     int lowerbound;
 14
 15     class counter
 16
 17     {
 18
 19         int count;
 20
 21     public:
 22
 23         counter(int n)
 24
 25         {
 26
 27             if ( n < upperbound)
 28
 29             {
 30
 31                 count = n;
 32
 33             }
 34
 35             else
 36
 37             {
 38
 39                 count = upperbound;
 40
 41             }
 42
 43         }
 44
 45
 46
 47         void reset( int n )
 48
 49         {
 50
 51             if ( n <= upperbound )
 52
 53             {
 54
 55                 count = n;
 56
 57             }
 58
 59         }
 60
 61
 62
 63         int run()
 64
 65         {
 66
 67             if ( count > lowerbound )
 68
 69             {
 70
 71                 return count--;
 72
 73             }
 74             else
 75             {
 76                 return lowerbound;
 77             }
 78         }
 79     };
 80 }
 81 int main()
 82
 83 {
 84
 85     //这里只是用CounterNameSpace中的upperbound
 86
 87     using CounterNameSpace::upperbound;
 88
 89
 90
 91     //此时对upperbound的访问就不需要使用范围限定符了
 92
 93     upperbound = 100;
 94
 95     //但是使用lowerbound的时候,还是需要使用范围限定符的
 96
 97     CounterNameSpace::lowerbound = 0;
 98
 99     CounterNameSpace::counter ob1(10);
100
101     int i;
102
103
104
105     do
106
107     {
108
109         i = ob1.run();
110
111         cout << i << " ";
112
113     }while( i > CounterNameSpace::lowerbound);
114
115     cout << endl;
116
117
118
119     //下面我们将使用整个CounterNameSpace的命名空间
120
121     using namespace CounterNameSpace;
122
123     counter ob2(20);
124
125     do
126
127     {
128
129         i = ob2.run();
130
131         cout << i << " ";
132
133     }while( i > CounterNameSpace::lowerbound);
134
135     cout << endl;
136
137
138
139     ob2.reset(100);
140
141     lowerbound = 90;
142
143     do
144
145     {
146
147         i = ob2.run();
148
149         cout << i << " ";
150
151     }while( i > lowerbound);
152
153
154
155     return 0;
156
157 }
158
159 上面的程序还为我们演示了重要的一点:当我们用using引入一个命名空间的时候,如果之前有引用过别的命名空间(或者同一个命名空间),则不会覆盖掉对之前的引入,而是对之前引入内容的补充。也就是说,到最后,上述程序中的std和CounterNameSpace这两个命名空间都变成全局空间了。
160
161 没有名称的命名空间
162
163 有一种特殊的命名空间,叫做未命名的命名空间。这种没有名称的命名空间使得我们可以创建在一个文件范围里可用的命名空间。其一般形式如下:
164
165 namespace
166
167 {
168
169     //声明
170
171 }

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

时间: 2024-10-06 04:24:02

C++命名空间详解的相关文章

Struts2之命名空间详解及JSP文件上传了解

学习案例:struts配置元素详解以及简单的jsp文件上传. 一.案例分析: a)将鼠标放在struts.xml中的package标签上.Alt+/会自动提示: 1.name 2.namespace 3.extends 4.externalReferenceResolver 5.abstract 6.strict-method-invocation b)abstract属性表示该包是抽象的,不能直接使用,需要有子包继承才能使用.Struts-default既是abstract,所以我们要继承使用

C#命名空间详解namespace

 命名空间是一个域,这在个域中所有的类型名字必须是唯一的,不同的类型分组归入到层次化的命名空间, 命名空间的好处是:1.避免名字冲突,2.便于查找类型名字. 如:System.secruity.Cryptogtaphy. 下面介绍namespace 关键字的使用. namespace test { class class0 { int i; public class0() { } }} using关键字使用 ,访问一个命名空间的内容可以通过完全限定名.如:test.class0来访问.但是每次这

jquery的事件命名空间详解

jquery现在的事件API:on,off,trigger支持带命名空间的事件,当事件有了命名空间,就可以有效地管理同一事件的不同监听器,在定义组件的时候,能够避免同一元素应用到不同组件时,同一事件类型之间的影响,还能控制一些意外的事件冒泡.在实际工作中,相信大家都用的很多,但是不一定了解它的所有细节,至少我有这样的经验,经常在碰到疑惑的时候,还得重新写例子去验证它的相关作用,所以本文想把事件命名空间相关的细节都梳理出来,将来再犯迷糊的时候可以回来翻着看看以便加深对它的理解和运用. 在详细了解命

命名空间详解和分类

命名空间是什么 计算机科学领域中是通过名字来使用各种代码资源(变量和子程序)的,命名空间(namespace)则是组织这些资源的一组符号,例如目录树是就硬盘上文件们的命名空间.命名空间的设计目的是提供一种让一组名称与其他名称分隔开的方式.在一个命名空间中声明的类的名称与另一个命名空间中声明的相同的类的名称不冲突. 如果你还是无法获得命名空间的概念,你只要想象给你一个1T的硬盘,但硬盘中无法创建文件夹,只能添加文件,你就能体会单一命名空间的坏处了,你必须保证1T的硬盘上所有文件的命名不能重复!这样

XML和Schema命名空间详解

来源:https://blog.csdn.net/wanghuan203/article/details/9204337 XML和Schema具有无关平台,技术厂商,简单,规范统一等特点,极具开放性,所以使用极为广泛,而且使用简单,在XML和Schema和,个人认为比较不好理解的一点是其命名空间问题,在这篇博客里详细进行理解. 名称空间是W3C推荐标准提供的一种统一命名XML文档中的元素和属性的机制.使用名称空间可以明确标识和组合XML文档中来自不同标记词汇表的元素和属性,避免了名称之间的冲突.

php命名空间详解

index.php: <?php include 'demo.php'; use A\demo as test; use B\demo as test2; use C\demo; $obj = new test(); $obj = new test2(); echo B\b."<br>"; class c extends demo{ } $obj = new c(); $obj -> say(); demo:php <?php namespace A; c

PHP中的命名空间(namespace)及其使用详解

PHP中的命名空间(namespace)及其使用详解 晶晶 2年前 (2014-01-02) 8495次浏览 PHP php自5.3.0开始,引入了一个namespace关键字以及__NAMESPACE__魔术常量(当然use关键字或use as嵌套语句也同时引入):那么什么是命名空间呢?php官网已很明确的进行了定义并形象化解释,这里直接从php官网copy一段文字[来源]. “什么是命名空间?从广义上来说,命名空间是一种封装事物的方法.在很多地方都可以见到这种抽象概念.例如,在操作系统中目录

python命名空间与闭包函数详解

python命名空间与闭包函数详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客主要介绍的知识点如下: 1>.三元运算 2>.命名空间 3>.global与nonlocal 4>.函数即变量 5>.嵌套函数 6>.闭包函数 一.三元运算 1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yi

YII2框架详解

yii2框架的安装我们在之前文章中已经提到下面我们开始了解YII2框架 Yii2的应用结构: 目录篇: advance版本的特点是:根目录下预先分配了三个模块,分别是前台.后台.控制台模块. 1.backend 它主要用于管理后台,网站管理员来管理整个系统. assets 目录用于存放前端资源包PHP类. 这里不需要了解什么是前端资源包,只要大致知道是用于管理CSS.js等前端资源就可以了. config 用于存放本应用的配置文件,包含主配置文件 main.php 和全局参数配置文件 param