名字空间 探讨!

      名字空间定义一个“用于声明的区域”。在C++程序设计环境中,变量、函数、类的名字曾经有过爆炸性的增长,在使用名字空间之前,所有这些名字都是在全局名字空间中,从而导致了大量的名字冲突。例如:如果你在程序中定义了一个函数toupper(),那么这个函数就会覆盖标准库中的函数toupper()(如果两个函数的参数列表相同).因为他们的名字都是在全局名字空间中的。如果在一个程序中使用两个或者多个第三方库,名字冲突将会变得更加复杂。在这种情况下,有可能---并且是极有可能---在一个库中定义的名字将会与另一个库中的同样名字发生冲突,特别是名字冲突涉及到类的名字时,将会更加麻烦。例如:如果在你的程序中定义了一个类VideoMode,而程序所用的库中也定义了一个同样名字的类,那么冲突就不可避免了。

      使用namespace关键字的目的就是为了解决上述问题,因为在名字空间中声明的名字只是在局部作用域可见,所以通过名字空间,我们就可以在不同的程序设计上下文中使用同样的名字而不会引起冲突。可能从namespace中受益最大的是C++标准库。在使用namespace之前,整个C++库是定义在名字空间std中,这就在很大程度上减少了名字冲突的可能性。你也可以在程序中创建自己的名字空间。并将你认为可能会造成冲突的名字定义在该名字空间中,这样,这些名字将只在局部作用域内可见,从而避免了名字冲突,当你创建类库或者函数库时,名字空间尤显重要。

1.1名字空间的基本概念

      你可以使用关键字namespace来创建声明区域,并以此来划分全局名字空间。从本质上来说,一个namespace也就定义了一个作用域,namespace的通用形式如下:

nameplates name

{

      //声明

}

所有在namespace语句中定义的元素都将限定在这个名字空间的作用域之内。下面的程序使用namespace将一个倒计数器类的名字局限在一个名字空间中,该名字空间定义了类counter,这个类实现的是一个倒计数器。该名字空间还定义了两个变量upperbound和lowerbound,分别用来存储计数器的上限值和下限值。

 

 

在上面的代码中,变量upperbound,lowerbound和类counter都限于由名字空间CounterNameSpace定义的作用域之内。名字空间中的代码可以直接使用在同一名字空间中定义的标识符,而不需要加上名字空间来限定。例如:在名字空间CounterNameSpace中,函数run可以直接使用lowerbound。如:if(count>lowerbound) return count--;然而,由于namespace定义了一个作用域,所以,如果名字作用域之外的代码要使用该名字空间之内的名字,那么就需要使用作用域解析运算符。例如:如果需要在CounterNameSpace之外将10赋给upperbound,那么你必须使用类似下面的语句:CounterNameSpace::upperbound=10;或者,如果你在CounterNameSpace之外声明一个counter类型的对象,那么必须使用下面这样的语句:CounterNameSpace::counter ob;通常名字空间之外代码要访问名字空间之内的成员时,需要在成员名之前加上名字空间和作用域解析运算符。下面的程序说明了名字空间CounterNameSpace的用法:

 

 

 

注意:在声明counter类型的对象以及使用变量upperboundlowerbound时都是用了名字空间CounterNameSpace以及作用域解析运算符。然而,在声明counter类型的对象之后,就不需要再次限定对象成员的作用域。也就是说,函数ob1.run()可以直接被调用,因为编译器已经知道了对象所在的作用域。

同一个名字可以用来声明若干个名字空间。这样,一个名字空间就被分散到几个文件,甚至是同一个文件之中。例如:

namespace NS{int i}      namespace NS{int j}      在上面的代码中,名字空间NS被划分成2个部分,然而,每个部分中的内容仍然是在同一个名字空间中。必须在其它类型作用域之外声明名字空间。例如:你不能在函数中声明一个名字空间。然而,一个名字空间可以嵌入到另一个名字空间之中。

1.2using

using将一个名字空间变为可见。你可能会想,如果在程序中要大量的使用某个名字空间中的成员,那么就不得不每次使用某个成员时加上名字空间名称好作用域解析运算符,这将会成为一项冗长而繁琐的工作。你可以使用using解决这个问题。using有2种通用的形式:

using namespace name;      using name::member;

第一种形式的using语句中,name是你需要使用的名字空间。所有定义在该名字空间的成员将变得可见(他们将成为当前名字空间--全局名字空间--中的一部分)。并且在使用这些成员时不需要加上作用域解析运算符。在第二种形式的using语句中,只有名字空间name中一个特定的成员时可见的。例如:对于上面示例中的名字空间CounterNameSpace,下面这些using语句和赋值语句是合法的:

 

在使用一个名字空间时,并不会覆盖当前的名字空间,当你将一个名字空间的成员变量可见时,实际上只是将该名字空间中的名字添加到当前名字空间中。即using之后,就把该名字空间中的全部变量,或者是指定的某个变量添加到全局名字空间中了。

1.3匿名名字空间

      匿名名字空间将标识符局限在声明的它们的文件中。还有一种特殊的名字空间,他允许你创建 在文件中 唯一的名字空间标识符。匿名名字空间的通用形式为:namespace {//声明部分}。匿名名字空间允许你建立一个唯一的名字空间。这个名字空间中的成员只有在定义它们的文件中才是可见的。也就是说,在包含匿名空间的文件中,可以直接使用名字空间的的成员而不需要限定符,但是在文件作用域之外,这些成员则是不可见的。使用static可以将一个全局变量限制在声明该变量的作用域之内。例如:

 

 

因为变量k是定义在file1中,所以它可以用在file1中。在file2中,k被指定为extern类型的变量,这意味着它的名字和类型定义在file2之外的文件中,然而k实际上并没有被定义。当这个两个文件链接时,file2在试图使用变量k的时候将会产生一个错误。因为兵没有变量k的定义。在file1中我们在变量k前面使用了static,因此k被限制在file1的作用域之内,对file2来说是不可见的。

尽管C++仍然允许在全局成员的声明中使用static,但是将一个标识符限制在某个文件作用域内还有一种更好的方法:使用匿名名字空间。例如:

 

 

在上面的示例中,变量k也是被限制在file1的作用域之内。标准C++推荐在新的代码中使用匿名名字空间而不是static来将全局成员限定在某个文件作用域之内。

典型的情况是,对于大多数小型和中型程序而言,你不需要创建名字空间。但是,如果要创建一个可重用的代码库,或者你想使你的代码有最大的可移植性,那么应该考虑将代码放在名字空间中。

2、std名字空间

std是c++标准库使用的名字空间。标准c++将它的整个库都定义在名字空间std中,因此,许多应用程序包含这条语句:

using namespace std;这条语句将名字空间std中的内容添加到当前名字空间中。这样,就可以直接访问定义在库中的类和函数,而不需要在每个名字前面加上std::。

当然,如果你愿意,也可以显式的用std::来限定每个名字的作用域。例如:在下面的程序中,标准库中的名字不会被全部添加到全局名字空间中:

 

上面的程序使用std::来显式的限制标准流对象cout和cin的作用域。也就是说,如果需要标准的输出对象,那么你必须使用std::cout语句;同样,如果需要标准的输入对象,那么必须使用std::cin语句。

如果在程序中只是有限制的使用到了标准库,你可能不想将整个标准c++库都引入到全局名字空间中。然而,如果你的程序使用了标准库中的上百个名字,那么就应该将名字空间std嵌入到当前的名字空间中,这比为每个名字分别添加限定符要容易的多。

如果你只用到标准库中的几个名字,那么可以对每个名字分别使用using语句来限定它们的作用域,这种方法的好处在于:在使用标准库名字的时候不需要std::限定符,然而也不需要将整个标准库都添加到全局名字空间中。例如:

 

在上面的程序中,对象cin和cout可以被直接使用,但是名字空间std中的其它内容将不会被引入到全局名字空间中。

前面说过,C++标准库最初是定义在全局名字空间中的,因此,如果你正在移植旧的C++代码,那么需要将using namespace std;包含在使用库的头文件中,或者在每个成员变量之前使用std::来限定作用域,尤其是当你使用新的头文件来取代原来的.h文件时,要更加注意。记住:旧的.h文件中的所有内容都被放入全局名字空间中,而新的头文件中的所有内容放在名字空间std中。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值