C Primer學習筆記 18 名字空間

2021-06-16 05:09:25 字數 4786 閱讀 9477

題記:本系列學習筆記(c++ primer學習筆記)主要目的是討論一些容易被大家忽略或者容易形成錯誤認識的內容。只適合於有了一定的c++基礎的讀者(至少學完一本c++教程)。

如果文中有錯誤或遺漏之處,敬請指出,謝謝!

名字空間定義

名字空間是乙個作用域,其形式以關鍵字namespace開始,後接名字空間的名字,然後一對大括號內寫上名字空間的內容。例如:

namespace test ;

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

int var; }

名字空間可以在全域性作用域或其他作用域內部定義,但不能在函式或類內部定義。可以在名字空間中放入可以出現在全域性作用域的任意宣告:類、變數(以及它們的初始化)、函式(以及它們的定義)、模板以及其他名字空間。

名字空間可以是不連續的,可以在幾個部分中定義,而名字空間由它的分離定義的部分的總和構成,即名字空間是累積的。乙個名字空間的分離部分可以分散在多個檔案中,在不同文字檔案中的名字空間定義也是累積的。但是,名字只在宣告名字的檔案中可見,這一常規限制繼續應用,所以,如果名字空間的乙個部分需要定義在另一檔案中的名字,仍然必須宣告該名字。

同時,名字空間的不連續性也意味著,可以用分離的介面檔案和實現檔案構成名字空間。因此,可以用與管理自己的類和函式定義相同的方法來組織名字空間:

1)定義類的名字空間成員,以及作為類介面的一部分的函式宣告與物件宣告,可以放在標頭檔案中,使用名字空間成員的檔案可以包含這些標頭檔案;

2)名字空間成員的定義可以放在單獨的原始檔中。

在名字空間內部定義成員時,跟在全域性範圍內定義是一樣的。也可以在名字空間定義的外部定義名字空間成員,用類似於在類外部定義類成員的方式:名字的名字空間宣告必須在作用域中,並且定義必須指定該名字所屬的名字空間。例如:

test::foo test::operator+ (const foo &lhs, const foo &rhs)

這個定義看起來類似於定義在類外部的類成員函式,返回型別和函式名由名字空間限定。一旦看到完全限定的函式名,就處於名字空間的作用域中。因此,形參表和函式體中的名字空間成員引用可以使用非限定名引用。

定義在全域性作用域的名字是定義在全域性名字空間(global namespace)中的。全域性名字空間是隱式宣告的,存在於每個程式中。在全域性作用域定義實體的每個檔案將那些名字加到全域性名字空間中。因為全域性名字空間是隱式的,沒有名字,所以用作用域操作符直接引用全域性名字空間的成員。

未命名的名字空間

名字空間也可以是未命名的,未命名的名字空間(unnamed namespace)在定義時沒有給定名字。未命名的名字空間與其他名字空間不同,未命名的名字空間的定義侷限於特定檔案,從不跨越多個檔案。未命名的名字空間中定義的名字只在包含該名字空間的檔案中可見,但其中的變數的生存期卻從程式開始到程式結束。如果有多個檔案包含未命名的名字空間,這些名字空間是不相關的,即使這些名字空間中定義了相同的名字,這些名字也代表不同的物件。未命名的名字空間中定義的名字可以直接使用,畢竟,沒有名字空間來限定它們。未命名的名字空間中定義的名字可以在定義該名字空間所在的作用域中找到。如果在檔案的最外層作用域中定義未命名的名字空間,那麼,未命名的名字空間中的名字必須與全域性作用域中的名字不同。特別注意:如果標頭檔案中定義了未命名的名字空間,那麼,在每個包含該標頭檔案的檔案中,該名字空間中的名字將定義不同的區域性物件。

未命名的名字空間的這種靜態特性,在c++中被用來取代c語言繼承而來的檔案中的靜態宣告。在標準c++中引入名字空間之前,程式必須將名字宣告為static,使它們區域性於乙個檔案。而引入名字空間後,c++不贊成檔案靜態宣告。不贊成的特徵也暗示著可能在將來的新標準中將不再支援這些特徵,所以應該避免檔案靜態而使用未命名的名字空間代替。

名字空間成員的使用

除了利用namespace_name::member_name這種形式使用名字空間中的成員外,可以利用三種方式實現更簡潔的使用,那就是using宣告、名字空間別名和using指示。

using宣告形如:using namespace_name::member_name;

乙個using宣告一次只引入乙個名字空間成員,它使得無論程式中使用哪些名字,都能夠非常明確。

using宣告的作用域遵循常規作用域規則:從using宣告點開始,直到包含該using宣告的作用域的末尾,名字都是可見的;外部作用域中定義的同名物件被遮蔽。

using宣告可以出現在全域性作用域、區域性作用域或者名字空間作用域中。類作用域中的using宣告侷限於被定義類的基類中定義的名字。

名字空間別名(namespace alias)將較短的名字與已存在的名字空間名相關聯。語法:以關鍵字namespace開頭,接(較短的)名字空間別名名字,再接=,再接原來的名字空間名字和分號。如果原來的名字空間名字是未定義的,則出錯。名字空間別名還可以引用巢狀的名字空間。例如:

namespace qlib = database::querylib;

using指示以關鍵字using開頭,後接關鍵字namespace,再接名字空間名字。如果該名字不是已經定義的名字空間名字,則出錯。using指示使得特定名字空間的所有名字可見,沒有限制。

用using指示引入的名字的作用域比using宣告的更複雜,它將名字空間成員提公升到包含名字空間本身和using指示的最近作用域的效果。這樣,該名字空間中的名字就可能與所提公升到的作用域內的物件名發生衝突。而using宣告將名字直接放入出現using宣告的作用域,好像using宣告是名字空間成員的區域性別名一樣。所以,使用using宣告是更好的選擇。

實參相關的查詢與類型別形參

對名字空間內部使用的名字的查詢遵循常規c++查詢規則,但有乙個遮蔽名字空間名字規則的乙個重要例外:接受類型別形參(或類型別指標及引用形參)的函式(包括過載操作符),以及與類本身定義在同一名字空間中的函式(包括過載操作符),在用類型別物件(或類型別的引用及指標)作為實參的時候是可見的(參見下面的過載與名字空間部分的例子)。例如:

std::string s;

// ok: calls std::getline(std::istream&, const std::string&)

getline(std::cin, s);

當編譯器看到getline函式的使用getline(std::cin, s);的時候,它在當前作用域、包含呼叫的作用域以及定義cin的型別和string型別的名字空間中查詢匹配的函式。因此,它在名字空間std中查詢並找到由string型別定義的getline函式。

如果函式具有類型別形參就使得函式可見,其原因在於,允許無須單獨的using宣告就可以使用概念上作為類介面組成部分的非成員函式。能夠使用非成員操作對操作符函式特別有用。例如:

std::string s;

cin >> s;

如果沒有上面這個規則,我們必須將其編寫為下面兩種形式之一:

using std::operator >>;          // neeed to allow cin >> s;

std::operator>>(std::cin, s);    // ok: explicitly use std::>>

顯然,沒上面的規則,對於這樣的io操作是極不方便的。

隱式友元宣告與名字空間

當乙個類宣告友元函式的時候,函式的宣告不必是可見的。如果不存在可見的宣告,那麼,友元宣告具有將該函式或類的宣告放入外圍作用域的效果。如果類在名字空間內部定義,則該友元函式相當於在這個名字空間中宣告了該函式。例如:

namespace a ;

}因為該友元接受類型別實參並與類隱式宣告在同一名字空間中,所以使用它時可以無須使用顯式名字空間限定符:

// f2 defined at global scope

void f2()

過載與名字空間

由於每個名字空間有自己的作用域,因此,作為兩個不同名字空間的成員的函式不能互相過載。但是,給定名字空間可以包含一組過載函式成員。一般而言,名字空間內部的函式匹配以與我們已經見過的方式進行:

1)找到候選函式集合。如果乙個函式在呼叫時其宣告可見並且與被呼叫函式同名,這個函式就是候選者;

2)從候選集合中選擇可行函式。如果函式的形引數目與函式呼叫的實參數目相同,並且每個形參都可用對應實參匹配,這個函式就是可行的。

3)從可行集合中選擇乙個最佳匹配,並產生**呼叫該函式。如果可行集合為空,則呼叫出錯,沒有匹配;如果可行集合非空且沒有最佳匹配,則呼叫有二義性。

名字空間對函式匹配有兩個影響:乙個影響是明顯的,即可用using宣告和using指示將函式加到候選集合;另乙個是微秒的。如前面所介紹,有乙個或多個類型別形參的函式的名字查詢包括定義每個形參型別的名字空間。這個規則還影響怎樣確定候選集合,為找候選函式而查詢定義形參類(以及定義其基類)的每個名字空間,將那些名字空間中任意與被呼叫函式名字相同的函式加入候選集合。即使這些函式在呼叫點不可見,也將之加入候選集合。例如:

namespace ns ;

void display(const item_base&) {}

}class bulk_item: public ns::item_base ;

int main ()

名字空間與模板

在名字空間內部宣告模板影響著怎樣宣告模板特化:模板的顯式特化必須在定義通用模板的命名空間中宣告,否則,該特化將與它所特化的模板不同名。

有兩種定義特化的方式:一種是重新開啟名字空間並加入特化定義;或者,可以用與在名字空間定義外部定義名字空間成員相同的方式來定義特化:使用由名字空間名字限定的模板名定義特化。

如果文中有錯誤或遺漏之處,敬請指出,謝謝!

[1] c++ primer(edition 4)

[2] thinking in c++(volume two, edition 2)

[3] international standard:iso/iec 14882:1998

xml學習5 名字空間

我們知道我們在c 中為了防止函式名字重複我們可以設定名字空間 在 xml中也是一樣 當引用兩個 xml文件的時候 可能出現 元素名字相同 但是意義不同的2個元素 xml解析器無法處理這種情況 這時候為了處理這種情況 於是就出現了名字空間的概念,xml中的名字空間很簡單 看下面是乙個簡單的名字空間 w...

c primer 學習筆記18 關聯容器

關聯容器和順序容器的本質差別在於 關聯容器通過鍵 key 儲存和讀取元素,而順序容器則通過元素在容器中的位置順序儲存和訪問元素。關聯容器 associative containers 支援通過鍵來高效地查詢和讀取元素。兩個基本的關聯容器型別是 map 和set。map 的元素以鍵 值 key val...

7 3 2 名字空間別名

1 名字空間別名定義根據下述語法為名字空間宣告了乙個可替代的名字 namespace alias identifier namespace alias definition namespace identifier qualified namespace specifier qualified na...