C++中的名字空间----避免名字冲突

名字空间是一种描述逻辑分组的机制。也就是说,如果有一些声明按照某种准则在逻辑上属于同一个集团,就可以将它们放在同一个名字空间,以表明这个事实。
  名字空间对于模块化的程序设计有重要作用。

  [1] 带限定词的名字
       因为名字空间就是作用域,所以普通的作用域规则也对名字空间成立。因此,如果一个名字先前已在空间或者外围作用域里声明过,就可以直接使用,不必再进一步为它操心了。也可以使用来自另一个名字空间的名字,但需要在名字空间作为限定词。
    典型用法如 std::cout<<..... ; 的使用,名字cout即是定义在标准名字空间std当中。

  [2] 使用声明
       显然,当某个名字在它自己的名字空间之外频繁使用时,在反复写它时都要加上名字空间来作限定词,是一件令人厌烦的事情。这时,可以通过一个使用声明而清楚掉,只需要在某个地方说明,在这个作用域其后的代码中,使用此名字时可以自动解析出此名字所在的空间。
     典型用法如 using std::cout; 此后在使用 cout 时,都无需再加上名字空间前缘了。

  [3] 使用指令
      一个使用指能把来自另一个名字空间的所有名字都变成在当前名字空间内可用,就像这些名字就在当前名字空间中一样。
   例如,在一个名字空间内有命令 using namespace std; 则在此后的代码中(当前空间最小局部内),对于所有名字都无需有名字空间前缀即可使用。
   应当理解,全局性的使用指令是一种完成转变的工具,而并不只是为了少拼写几个名字空间,在其它方面最好避免使用它,因为他因引入同义词而导致混乱。
   在一个名字空间里的使用指令是一种名字空间的组合工具。
   在一个函数里(也仅限于这种地方),可以安全的将使用指令作为一个方便的记法方式。

  [4] 避免名字冲突
      名字空间是为了表示逻辑结构。最简单的这类结构就是分清楚由一个人写的代码与另一个人写的代码。这种简单的划分也可能具有极大的实际重要性。通过上面介绍的三种技术,通过显示的限定,使用声明或者使用指令去使用不同名字空间中可能重复的名字

  [5] 无名的名字空间
      在一些情况下,名字空间的作用仅仅是为了保持代码的局部性,这时去发明一个多余的名字就成了人烦恼,还可能偶然地与其它名字相冲突。此时,可以简单的让这个名字空间没有名字。
      如:
         namespace {
               int a;    void f(){ }
         }
      显然,必须存在某种方式,使我们可以从一个无名的名字空间之外访问其中的成员。因此,无名空间有一个隐含的使用指令。上面的声明等价于
        namesapce $$${
               int a;     void f(){}
        }
        using namespace $$$

  [6]名字空间的别名
     如果用户给他们的名字空间名字起得太短,不同名字空间也可能引起冲突;而名字空间太长可能又变得不很实用。这时,可以通过在使用指令中给名字空间提供一个别名来改善情况。
     如:namespace s = std; 之后,可以用s来代表名字空间std,s::cout <<... ;

  [7] 组合和选择
       我们常常需要从现存的界面出发组合出新的界面.方法是在新界面中用使用指令引入已有的界面。在使用新界面的名字时,如果显式限定的名字在所说的名字空间里没有声明,编译器就会查看使用指令说到的名字空间。
       只有在我们需要定义什么东西时,才需要知道一个实体真正所在的名字空间。
       有时我们只是想从一个名字空间里选用几个名字,通过使用声明来做,可以使从名字空间里选择一些特征的变得更加明确。使用声明将具有指定的名字的每个声明都带入作用域。特别的,通过一个使用声明,将一个重载函数的所有变形都带进来。
      
       将组合(通过使用指令)和选择(通过使用声明)结合起来能产生更多的灵活性,这些也都是真实世界的例子所需要的。依靠这种机制,我们能有这样的方式,它们既能提供许多机制的访问,又能消解由于组合而产生的名字冲突或者歧义性。(在查看一个名字空间时,通过显示声明的方式(包括通过使用声明声明的名字)优先于在其它作用域的那些通过使用指令才能访问的名字。

  [8] 名字空间和重载
      重载可以跨名字空间工作。对于我们能以最小代价将现存的库修改为使用名字空间的东西而言,这特征是必不可少的。


名字空间允许像类,对象和函数一样的一组实体归属于一个名称。把一个全局的范围化分成许多子的范围,每一个小的范围都有它自己的名字。

名字空间的格式是:

namespaceidentifier{

entities

}


包含在名字空间下的任何类,对象和函数中设立的实体必须是有效的标签符,例如:

namespace myNamespace{

int a, b;

}


这种情况,在被调用的名字空间myNamespace内部变量a和变量b被定义成了一个普通的变量,为了从myNamespace外部访问这些变量,我们必须使用作用域操作符::,例如,从myNamespace外部访问前面定义的变量,我们要这样写:

general::a

general::b



名字空间的功能一个全局的对象或者函数像另外一个对象一样使用了同一个标识符时特别有用,会引起重定义的错误,例如:

//namespace

#include <iostream>

using namespace std;

namespace first{

int var = 5;

}

namespace second{

double var = 3.1416;

}

int main() {

cout << first::var << endl;

cout << second::var <<endl;

return 0;

}



程序运行如下:

5

3.1416



这种情况我们使用了两个相同名字的全局变量:var。一个是被定义在first名字空间里的,另一个是被定义在second名字空间内的。因为有了名字空间所以没有发生重定义的错误。


using

使用using这个关键字是为了将一个来到名字空间内的名字介绍到当前声明的区域,例如:


//namespace

#include <iostream>

using namespace std;

namespace first{

int x = 5;

int y = 10;

}

namespace second{

double x = 3.1416;

double y = 2.7183;

}

int main() {

using first::x;

using second::y;

cout << x << endl;

cout << y <<endl;

cout <<first::y <<endl;

cout <<second::x <<endl;

return 0;

}



程序运行如下:


5

2.7183

10

3.1416



如何注意这段代码,x(没有任何名字空间标识符)是引用first::x,而y引用second::y,正是由于我们在前面指定了using这个声明,所以们仍然要使用标识符全名来访问first::ysecond::x

关键字using也能直接指向一个实体名字空间。


//namespace

#include <iostream>

using namespace std;

namespace first{

int x = 5;

int y = 10;

}

namespace second{

double x = 3.1416;

double y = 2.7183;

}

int main() {

using namespace first;

cout << x << endl;

cout << y <<endl;

cout <<second::x <<endl;

cout <<second::y <<endl;

return 0;

}


程序运行如下:


5

10

3.1416

2.7183


这个情况,我们定义过using namespace frist,所有直接使用xy没有使用名字空间标识符而是引用了定义的名字空间frist


usingusing namespace 仅仅是在同一个块里有效,它们规定在整个代码内,是否是在全局范围里直接使用,例如,如果我们打算首先使用一个名字空间的对象,再使用别外一个名字空间的对象,我们应该这样做:

//namespace

#include <iostream>

using namespace std;

namespace first{

int x = 5;

}

namespace second{

double x = 3.1416;

}

int main() {

using namespace first;{

cout << x << endl;

}{

using namespace second;

cout << x <<endl;

}

return 0;

}


程序运行如下:


5

3.1416


名字空间别名(Namespace alias)

我们能改变一个已经存在的名字空间的命名,相应的格式如下:


namespace new_name = current_name;


名字空间std (namespace std)

C++标准类库中的所有实体都定义在名字空间std中,这就是为什么我们通常需要包含一个using namespace std,描述在所有的程序中使用的实体都定义在iostream中。


你可能感兴趣的:(C++中的名字空间----避免名字冲突)