c++命名空间

  命名空间(Namespace)表示标识符(identifier)的可见范围。一个标识符可在多个命名空间中定义,它在不一样命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,由于已有的定义都处于其它命名空间中。c++

  例如,设BillX公司的员工,工号为123,而JohnY公司的员工,工号也是123。因为两人在不一样的公司工做,可使用相同的工号来标识而不会形成混乱,这里每一个公司就表示一个独立的命名空间。若是两人在同一家公司工做,其工号就不能相同了,不然在支付工资时便会发生混乱。编程

  这一特色是使用命名空间的主要理由。在大型的计算机程序或文档中,每每会出现数百或数千个标识符。命名空间(或相似的方法,见命名空间的模拟一节)提供一隐藏区域标识符的机制。经过将逻辑上相关的标识符组织成相应的命名空间,可以使整个系统更加模块化。编程语言

  在编程语言中,命名空间是一种特殊的做用域,它包含了处于该做用域内的标识符,且自己也用一个标识符来表示,这样便将一系列在逻辑上相关的标识符用一个标识符组织了起来。许多现代编程语言都支持命名空间。在一些编程语言(例如C++和Python)中,命名空间自己的标识符也属于一个外层的命名空间,也即命名空间能够嵌套,构成一个命名空间树,树根则是无名的全局名空间。ide

  函数和类的做用域可被视做隐式命名空间,它们和可见性、可访问性和对象生命周期不可分割的联系在一块儿。模块化

 

C++中的命名空间

C++语言中,命名空间使用namespace来声明,并使用{ }来界定命名空间的做用域. 例:wordpress

namespace foo {  

  int bar;

}

命名空间能够是全局的,也能够位于另外一命名空间之中;但不能在类和代码块之中。因此,在命名空间中声明的名称,默认具备外部连接特性(除非声明了常量,常量默认是静态于一个编译单元)。函数

在全部命名空间以外,还存在一个全局命名空间,对应于不使用命名空间时的全局做用域。例如,::new是全局new运算符。google

按照是否有名字,可分为有名字的命名空间与无名命名空间。后者为:spa

namespace {              

  namespace-body(即声明序列(可选))

       }

无名命名空间的成员在本编译单元中能够不加显式引用(实际上也无法显示引用无名名字空间)而直接使用;但在其余编译单元中不可见。即具备内部连接属性。code

命名空间的成员,是在命名空间体的花括号内声明了的名称。能够在命名空间体以外,给出命名空间成员的定义。即命名空间的成员声明与定义能够分开。

子命名空间必须定义在上层命名空间体以内。禁止把子命名空间的声明与定义分开。

不能以命名空间名::成员名;”方式,在命名空间体以外为命名空间添加新成员.必须在命名空间体之中添加新成员的声明。

能够屡次声明和定义同一命名空间,每次给这一命名空间添加新成员。编译器自动合并这些同名的命名空间。(实际上编译器并不合并一个命名空间、也不枚举一个命名空间有哪些成员。编译器仅仅是给全部命名空间的成员加上名字限定符qualifier做为其装饰名字mangling name

能够在一个命名空间中引入其余命名空间的成员。例如:

namespace myNameSpace{

       using namespace His_NameSpace;

       using OLib::List;

       void my_func(String &, List &);

}


引用命名空间的成员,有下述办法:

  • 使用命名空间的做用域解析运算符::,如:std::cout
  • using namespace 命名空间名[::命名空间名…];该语句使指定的命名空间中的全部成员均可直接使用。若是引入的名称与局部名称发生冲突,则编译器并不会发出任何警告信息,而只是用局部名称自动覆盖命名空间中的同名成员。
  • using 命名空间名::[命名空间名::……]成员名; 引入命名空间中的一个成员。若是引入的名称与局部名称发生同名冲突,编译器会报错。

命名空间能够有别名:namespace 别名 = 命名空间名; 这使得名字较长的命名空间能够方便地用较短的别名来引用。

原文连接:命名空间

 

未命名的命名空间

  未命名的命名空间(unnamed namespace)是指关键字namespace后紧跟花括号括起的一系列声明语句。未命名的命名空间中定义的变量拥有静态生命周期:它们在第一次使用前建立,而且直到程序结束才销毁。

  

  一个未命名的命名空间能够在某个给定文件内不连续,可是不能跨越多个文件。每一个文件定义本身的未命名的命名空间,若是两个文件都含有未命名的命名空间,则这两个空间互相无关。在这两个未命名的命名空间中能够定义相同的名字,而且这些定义表示的是不一样实体。若是一个头文件定义了未命名的命名空间,则该命名空间中定义的名字将在每一个包含了该头文件的文件中对应不一样的实体。和其余命名空间不一样,未命名的命名空间仅在特定文件内部有效,其做用范围不会横跨多个做用范围。

  

  定义在未命名的命名空间中的名字能够直接使用,毕竟咱们找不到什么命名空间的名字来限定它们:一样的咱们也不能对未命名的命名空间成员使用做用域运算符。

  

  未命名的命名空间做用域的一个应用:

若是你在一个 source1.cc中

     //source1.cc
     int x;
     int x;

出现两次 int x; int x;即两个x的定义,会编译报错,x重复定义。

若是你的

     //source1.cc
     int x;
     //source2.cc
     int x;
     g++ –o test source1.cc source2.cc

那么编译过程不会出错,在连接过程,因为目标代码中有两个全局域的x,会连接出错,x重定义。

不一样的编程人员可能会写不一样的模块,那么很容易出现这种状况,如何避免呢,namespace能够避免重名。google 编程规范鼓励使用不具名空间

     //source1.cc
     namespace {
     int x;
     }
     //source2.cc
     namespace {
     int x;
     }

OK,如今不会连接出错了由于两个x不重名了,固然对于这个简单的例子只在source1.cc中用不具名命名空间就可避免连接出错了。

  ////source1.cc
     namespace {
     int x;
     }
    //source1.cc
    static int x;

有什么区别呢,看上去效果同样,区别在于不具名空间的x仍然具备外连接,可是因为它是不具名的,因此别的单元没办法连接到,若是

   namespace haha{
   int x;
   }  

则在别的单元能够用haha::x访问到它,static 则由于是内部连接特性,因此没法连接到。

C++ 中 static 和 anonymouse namespace 的差异

记得之前一个同事问我为何程序里使用了 anonymouse namespace ,想了想 就回答说其实就是保持局部性(这也是个人目的),而后就有人说为何不用static,嗯 彷佛这两个东西乍一看没什么区别,本身便Google了一下,发现有一个缘由就是 anonymousenamespace 里的 member 都是有外部连接的,只不过永远都不能被外部link到!而 static 就明确为根本没有外部连接!此时就出现问题了,在模板里无类型的参数必须是有外部连接的才能够,不然编译没法通;好比:

template <void fn()> 
class Foobar {};
namespace { 
    void abc() 
    {
         wcout<<_T(”abc”)<<endl;
     }
} 
static void efg() 
{
     wcout<<_T(”efg”)<<endl;
}
int _tmain(int argc, _TCHAR* argv[]) 
{
     Foobar<abc>xyz //! ;这一行能够经过 
     Foobar<efg>rst; //! 注意这一行编译不过
     return 0; 
} 
    

在《c++ primer 第五版》书中指出,在文件中进行静态声明的作法已经被c++标准取消了,如今的作法是使用未命名的命名空间。

相关文章
相关标签/搜索