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++標準取消了,如今的作法是使用未命名的命名空間。

相關文章
相關標籤/搜索