C++必知必会之(23)名字空间

1、全局作用域日益变得拥挤不堪。

例如,许多库都希望包括一个名为String的类。但是,如果使用两个不同的库,其中分别定义了一个string类型,就会产生多重定义错误甚至更糟。


2、本质上,名字空间是对全局作用域的细分:

namespace  org_semantics    {

        class String {  ....  };

        String operator + ( const String &,  const String & );

        //其他类、函数、类型定义等...

}

这个代码片段打开了一个名为org_semantics的名字空间,声明了一些有用的东西,然后采用闭花括号关闭该名字空间。总是可以向一个名字空间加入更多的东西,只要重复上述过程。

名字空间对所有人都是“开放”的。


可以注意到名字空间org_semantics中有些名字只有声明而没有定义。为了给这些名字提供定义,可以重新打开该名字空间:

namespace  org_semantics  {

     String  operator + ( const  String &a,   String &b )    {     //......    }

}


3、还有一种选择,就是可以仅仅为该定义加上名字空间限定而无需重新打开名字空间:

org_semantics::String

org_semantics::operator + ( const org_semantics::String  &a,    const org_aemantics::String &b )

{   //.....   }

这种方式可以防止一不小心声明了一个新的名字空间(正如我们在第一个operator+定义中遗漏了对第二个参数进行const修饰那样),而不是定义了一个已经声明的空间。


4、如果希望使用定义于一个特有名字空间中的名字,必须告诉编译器该名字可以在哪一个名字空间中找到:

org_semantics::String  s ( " Hello, World!" );


尽管一些C++标准库组件还呆在全局作用域中(这些组件包括全局operator new、operator delete、array new以及array delete等),然而大多数标准库组件现驻留在std(意指standard标准)名字空间中,因而对大多数标准库组件的使用,需要限定std名称:

#include<iostream>

#include<vector>

//....

void aFunc ( )  {

    vector<int> a;                   //错误,没看到哪里定义了vector

     std::vector<int >  b;             //ok

     cout<<" opo" <<endl;            //错误

     std::cout<< "Better!"<<std::endl;            //ok

     //....

}


显然,连续使用显式的限定符很乏味。缓解方式是使用using指令:

void aFunc( )  {

     using namespace std;     //using 指令

     vector<int >   a;           //ok

     cout<<"Hello"<<endl;           //ok

      //...

}


从本质上讲,using指令从名字空间中导入名字,使它们在该using指令的作用域内无需进行限定就可以被访问

在本例中,using指令的作用域一直延伸到函数体末尾,后面再想使用该名字空间的东西,还需进行明确的限定。

正因为因为如此,许多C++程序员建议将using指令放在全局作用域中:

#include<iostream>

#include<vector>

using namespace std;

using namespace org_sematics;

这是个馊主意!

如此一来,名字空间中的所有名字在任何地方都可以被访问了,从而可能导致混淆。

在头文件中这么做更糟糕,因为所有包含该头文件的文件都会受到影响。

在头文件中,我们通常坚持使用显式的限定,并且仅将using指令局限于较小的作用域中(例如函数体或函数体内的某个代码块),这样它们的效用就会受到限制并易于控制。

基本来说,在头文件中要坚持表现得最好,在源文件中要表现的足够好,而在函数体内大可放松一下。


5、使用using指令的一个有趣的方面在于,它使一个名字空间中的名字变得可用,但这种“可用”又不能算是绝对的可用,其实际效果相当于该名字空间中的名字被声明在全局作用域中,而非局限于using指令所在的作用域中。

所以说,如果using指令作用域中出现同名名字,就会隐藏该名字空间中的相应名字:

void aFunc( )  {

      using namespace std;          //using 指令

      //....

      int vector = 12;                  //一个欠佳的具名局部变量

      vector<int > a;                  //错误!std::vector被隐藏了

      std::vector< int> b;           //ok,可以使用显式的限定

       //....

}


6、另一种方法是使用using声明,它通过一个真正的声明提供对名字空间中名字的访问:

void aFunc( )   {

       using std::vector;          //using声明

        //....

        int vector = 12;             //错误!重新声明vector

        vector<int >  a;            //ok

        //....

}

using声明通常是介于冗长乏味的显式限定和不受限制地使用using指令之间的一种折中。


7、另一种方式是使用别名:

namespace S = org_semantics;

现在S可以用于代替org_semantics(在别名的作用域内)。与using指令一样,最好避免在头文件中使用名字空间别名(毕竟S远比org_sematics更容易与其他名字冲突)。

              


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值