在网络看了这篇文章,感觉还是不错的,转载过来。
其实命名空间的含义是很好明白的:就是对相同名称的类分配到不同的组中,这个组名就是命名空间的名称。如同一公司有两个名字相同的员工,但属于不同的部门,开会点到时,只要点名时,前面加上部门,就能区别这两个人。
C++中的命名解决了这样一个问题。没有出现在命名空间以前,所有类名都是不能重名的。有了命名空间,只要不在一个命名空间中,相同名称的类也可以在上下文中使用。其实命名空间也为写程序带来了灵活性,可以使用C++中的标准库,还可以使用其它库,如QT,MFC什么的。
使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突。在C++中,变量、函数和类都是大量存在的。如果没有命名空间,这些变量、函数、类的名称将都存在于全局命名空间中,会导致很多冲突。比如,如果我们在自己的程序中定义了一个函数toupper(),这将重写标准库中的toupper()函 数,这是因为这两个函数都是位于全局命名空间中的。命名冲突还会发生在一个程序中使用两个或者更多的第三方库的情况中。此时,很有可能,其中一个库中的名 称和另外一个库中的名称是相同的,这样就冲突了。这种情况会经常发生在类的名称上。比如,我们在自己的程序中定义了一个Stack类,而我们程序中使用的某个库中也可能定义了一个同名的类,此时名称就冲突了。
Namespace关键字的出现就是针对这种问题的。由于这种机制对于声明于其中的名称都进行了本地化,就使得相同的名称可以在不同的上下文中使用,而不会引起名称的冲突。或许命名空间最大的受益者就是C++中的标准库了。在命名空间出现之前,整个C++库都是定义在全局命名空间中的(这当然也是唯一的命名空间)。引入命名空间后,C++库就被定义到自己的名称空间中了,称之为std。这样就减少了名称冲突的可能性。我们也可以在自己的程序中创建自己的命名空间,这样可以对我们认为可能导致冲突的名称进行本地化。这点在我们创建类或者是函数库的时候是特别重要的。
命名空间基础
namespace关键字使得我们可以通过创建作用范围来对全局命名空间进行分隔。本质上来讲,一个命名空间就定义了一个范围。定义命名空间的基本形式如下:
namespace 名称{//声明}
在命名空间中定义的任何东西都局限于该命名空间内。
下面就是一个命名空间的例子,其中对一个实现简单递减计数器的类进行了本地化。在该命名空间中定义了计数器类用来实现计数;其中的upperbound和lowerbound用来表示计数器的上界和下界。
- //演示命名空间
- namespace CounterNameSpace
- {
- int upperbound;
- int lowerbound;
- class counter
- {
- int count;
- public:
- counter(int n)
- {
- if ( n <= upperbound )
- {
- count = n;
- }
- else
- {
- count = upperbound;
- }
- }
- void reset(int n)
- {
- if ( n < upperbound )
- {
- count = n;
- }
- }
- int run()
- {
- if ( count > lowerbound)
- {
- return count--;
- }
- else
- {
- return lowerbound;
- }
- }
- }
- }
其中的upperbound,lowerbound和类counter都是有命名空间CounterNameSpace定义范围的组成部分。
在命名空间中声明的标识符是可以被直接引用的,不需要任何的命名空间的修饰符。例如,在CounterNameSapce命名空间中,run()函数中就可以直接在语句中引用lowerbound:
if ( count > lowerbound)
{
return count--;
}
然而,既然命名空间定义了一个范围,那么我们在命名空间之外就需要使用范围解析运算符来引用命名空间中的对象。例如,在命名空间CounterNameSpace定义的范围之外给upperbound赋值为10,就必须这样写:
CounterNameSpace::upperbound = 10;
或者在CounterNameSpace定义的范围之外想要声明一个counter类的对象就必须这样写:
CounterNameSpace::counter obj;
一般来讲,在命名空间之外想要访问命名空间内部的成员需要在成员前面加上命名空间和范围解析运算符。
下面的程序演示了如何使用CounterNameSpace这个命名空间:
- //演示命名空间
- #include <iostream>
- using namespace std;
- namespace CounterNameSpace
- {
- int upperbound;
- int lowerbound;
- class counter
- {
- int count;
- public:
- counter(int n)
- {
- if ( n <= upperbound )
- {
- count = n;
- }
- else
- {
- count = upperbound;
- }
- }
- void reset(int n)
- {
- if ( n < upperbound )
- {
- count = n;
- }
- }
- int run()
- {
- if ( count > lowerbound)
- {
- return count--;
- }
- else
- return lowerbound;
- }
- }
- }
- int main()
- {
- CounterNameSpace::upperbound = 100;
- CounterNameSpace::lowerbound = 0;
- CounterNameSpace::counter ob1(10);
- int i;
- do
- {
- i = ob1.run();
- cout << i << " ";
- } while (i > CounterNameSpace::lowerbound);
- cout << endl;
- CounterNameSpace::counter ob2(20);
- do
- {
- i = ob2.run();
- cout << i << " ";
- } while (i > CounterNameSpace::lowerbound);
- cout << endl;
- ob2.reset(100);
- do
- {
- i = ob2.run();
- cout << i << " ";
- } while (i > CounterNameSpace::lowerbound);
- cout << endl;
- return 0;
- }
请注意:counter类以及upperbound和lowerbound的引用都是在前面加上了CounterNameSpace修饰符。但是,一旦声明了counter类型的对象,就没有必须在对该对象的任何成员使用这种修饰符了。因此ob1.run()是可以被直接调用的。其中的命名空间是可以被解析的。
相同的空间名称是可以被多次声明的,这种声明向相互补充的。这就使得命名空间可以被分割到几个文件中甚至是同一个文件的不同地方中。例如:
- namespace NS
- {
- int i;
- }
- //...
- namespace NS
- {
- int j;
- }
其中命名空间NS被分割成两部分,但是两部分的内容却是位于同一命名空间中的。也就是NS。最后一点:命名空间是可以嵌套的。也就是说可以在一个命名空间内部声明另外的命名空间。
using关键字
如果在程序中需要多次引用某个命名空间的成员,那么按照之前的说法,我们每次都要使用范围解析符来指定该命名空间,这是一件很麻烦的事情。为了解决这个问题,人们引入了using关键字。using语句通常有两种使用方式:
using namespace 命名空间名称;
using 命名空间名称::成员;
第一种形式中的命名空间名称就是我们要访问的命名空间。该命名空间中的所有成员都会被引入到当前范围中。也就是说,他们都变成当前命名空间的一部分了,使用的时候不再需要使用范围限定符了。第二种形式只是让指定的命名空间中的指定成员在当前范围中变为可见。我们用前面的CounterNameSpace来举例,下面的using语句和赋值语句都是有效的:
- using CounterNameSpace::lowerbound; //只有lowerbound当前是可见的
- lowerbound = 10; //这样写是合法的,因为lowerbound成员当前是可见的
- using CounterNameSpace; //所有CounterNameSpace空间的成员当前都是可见的
- upperbound = 100; //这样写是合法的,因为所有的CounterNameSpace成员目前都是可见的
- //使用using
- #include <iostream>
- using namespace std;
- namespace CounterNameSpace
- {
- int upperbound;
- int lowerbound;
- class counter
- {
- int count;
- public:
- counter(int n)
- {
- if ( n < upperbound)
- {
- count = n;
- }
- else
- {
- count = upperbound;
- }
- }
- void reset( int n )
- {
- if ( n <= upperbound )
- {
- count = n;
- }
- }
- int run()
- {
- if ( count > lowerbound )
- {
- return count--;
- }
- ...