名称空间

来源:互联网 发布:好网角自动发帖软件 编辑:程序博客网 时间:2024/04/28 12:00

在C++中,名称可以是变量、函数、结构、枚举、类以及类和结构的成员。

1 传统的C++名称空间

第一个需要知道的术语是声明区域。声明区域是可以在其中进行声明的区域。例如,可以在函数外面什么全局变量,对于这种变量,其声明区域为其声明所在的文件。对于在函数中声明的变量,其声明区域为其声明区域所在的代码块。
第二个需要知道的术语是潜在作用域。变量的潜在作用域从声明点开始,到其声明区域的结尾。因此潜在作用域比声明区域小,这是由于变量必须定以后才能使用。
然而,变量并非在其潜在作用域内的任何位置都是可见的。例如,它可能被另一个在嵌套声明区域中声明的同名变量隐藏。变量对程序而言可见的范围被称为作用域。

2 新的名称空间特性

C++新增了这样一种功能,即通过定义一种新的声明区域来创建命名的名称空间。这样做的目的之一是提供了一个声明名称的区域。一个名称空间中的名称不会与另外一个名称空间的相同名称发生冲突,同时允许程序的其他部分使用该名称空间中声明的东西。
例如:
namespace Jack{       double pail;       void fetch();        int pal;        struct well{...};}namespace Jill{        double bucket(double n){...};        double fetch;        int pal;        struct Hill{...};}
名称空间可以是全局的,也可以是位于另一个名称空间中,但不能位于代码块中。因此,在默认情况下,在名称空间中声明的名称的链接性为外部的(除非它引用了常量)。
除了用户定义的名称空间外,还存在另一个名称空间——全局名称空间。它对应于文件级声明区域,因此前面所说的全局变量现在被描述为位于全局名称空间中。
名称空间是开放的,即可以把名称加入到已有的名称空间中。例如
namespace Jill{      char *goose(const char*);}

当然,需要有一种方法来访问给定名称空间中的名称。最简单的方法是,通过作用域解析运算符::,使用名称空间来限定该名称:
Jack ::pail=12.34;Jill::Hill mole;Jack::fetch();

未被装饰的名称(如pail)称为未限定的名称;包含名称空间的名称(如Jack::pail)称为限定的名称。

1)using 声明和using编译指令
我们并不希望每次使用名称时都对它进行限定,因此C++提供了两种机制(using声明和using编译指令)来简化对名称空间中名称的使用。using 声明使特定的标识符可用,using编译指令使整个名称空间可以。

using声明由被限定的名称和它使用的关键字using组成:
using Jill::fetch;

using 声明将特定的名称添加到它所属的声明区域中。例如main()中的using声明Jill::fetch将fetch添加到main()定义的声明区域中。完成该声明后,便可以使用名称fetch代替Jill::fetch。下面的代码段说明了这几点:

由于using声明将名称添加到局部声明区域中,因此这个示例避免了将另一个局部变量也命名为fetch。另外,和其他局部变量一样,fetch也将覆盖同名的全局变量。

在函数外面使用using声明时,将被名称添加到全局名称空间中:


using声明使一个名称可用,而using编译指令是所有的名称可用。using编译指令由名称空间名和他前面的关键字using namespace组成,它使名称空间中的所以名称都可用,而不需要使用作用域解析运算符:

using namespace Jack;

在全局声明区域中使用using编译指令,将使该名称空间的名称全局可用。

在函数中使用using编译指令,将使其中的名称在该函数中可用。

2)using编译指令和using声明之比较

使用using编译指令导入仪名称空间中所有的名称与使用多个using声明是不一样的,而更像是大量使用作用域解析运算符。使用using声明时,就好像声明了相应的名称一样。如果某个名称已经在函数中声明了,则不能用using声明导入相同的名称。然而,使用using编译指令时,将进行名称解析,就像在包含using声明和名称空间本身的最小声明区域中声明了名称一样。在下面的示例中,名称空间为全局的。如果使用using编译指令导入一个已经在函数中声明的名称,则局部名称将隐藏名称空间名,就像隐藏同名的全局变量一样。不同仍可以像下面的示例那样使用作用域解析运算符;


注意:假设名称空间和声明区域定义了相同的名称。如果试图使用using声明将名称空间的名称导入该声明区域,则这两个名称会发生冲突,从而出错。如果使用using编译指令将该名称空间的名称导入该声明区域,则局部版本将因此名称空间版本。

一般说来,使用using声明比使用using编译指令更安全,这是由于它只导入指定的名称。如果该名称与局部名称发生冲突,编译器将发出指示。using编译指令导入所有的名称,包括可能并不需要的名称。如果与局部名称发生冲突,则局部名称将覆盖名称空间版本,而编译器并不会发生警告。另外,名称空间的开放意味着名称空间的名称可能分散在多个地方,这使得难以准确知道添加了哪些名称。
#include<iostream>int main(){using namespace std;#include<iostream>using namespace std;int main(){int x;std::cin>>x;std::cout<<x<<std::endl;或者using std::cin;using std::cout;using std::endl;int x;cin>>x;cout<<x<<endl;

3)名称空间的其他特性

可以将名称空间声明进行嵌套:
namespace elements{       namespace fire       {           int flame;           .....         }         float water;}

这里,flame指的是elements::fire::flame。同样,可以使用下面的using编译指令使内部的名称可以:
using namespace elements::fire;

4)未命名的名称空间
可以通过省略名称空间的名称来创建未命名的名称空间:

namespace{     int ice;     int bandycoot;}

这就像后面跟着using 编译指令一样,也就是说,在该名称空间中声明的名称的潜在作用域:从声明点到该声明区域末尾。从这方面看,它们与全局变量相似。然而,由于这种名称空间没有名称,因此不能显式地使用using编译指令或using声明来使用它在其他位置都可用。具体地说,不能在未命名名称空间所属文件之外的其他文件中,使用该名称空间的名称。这提供了链接性为内部的静态变量的替代品。例如:

0 0