命名空間
命名空間(英語:Namespace),也稱名字空間、名稱空間等,它表示着一個識別碼(identifier)的可見範圍。一個識別碼可在多個命名空間中定義,它在不同命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何識別碼,它們不會與任何已有的識別碼發生衝突,因為已有的定義都處於其他命名空間中。
例如,設Bill是X公司的員工,工號為123,而John是Y公司的員工,工號也是123。由於兩人在不同的公司工作,可以使用相同的工號來標識而不會造成混亂,這裏每個公司就表示一個獨立的命名空間。如果兩人在同一家公司工作,工號也相同,便會發生混亂。
這一特點是使用命名空間的主要理由。在大型的電腦程式或文件中,往往會出現數百或數千個識別碼。命名空間提供一隱藏區域識別碼的機制。[1]通過將邏輯上相關的識別碼組織成相應的命名空間,可使整個系統更加模組化。
在程式語言中,命名空間是對作用域的一種特殊的抽象,它包含了處於該作用域內的識別碼,且本身也用一個識別碼來表示,這樣便將一系列在邏輯上相關的識別碼用一個識別碼組織了起來。許多現代程式語言都支援命名空間。在一些程式語言(例如C++和Python)中,命名空間本身的識別碼也屬於一個外層的命名空間,也即命名空間可以巢狀,構成一個命名空間樹,樹根則是無名的全域命名空間。
C++中的命名空間
在C++語言中,命名空間是一種實體(entity),使用namespace來聲明,並使用{ }來界定命名空間體(namespace body)。
例:
namespace foo {
int bar;
}
C語言的全域作用域對應於C++全域命名空間作用域。全域命名空間不需要聲明也無法顯式聲明。使用時,可以用字首為::
的qualified-id顯式限定全域命名空間作用域中的名稱。例如,::operator new
指稱全域new運算子函數。
命名空間可以在另一命名空間之中巢狀聲明;但不能聲明在類和代碼塊之中。在命名空間中聲明的名稱,預設具有外部連結屬性(除非聲明的是const對象,它預設是具有內部連結屬性)。
按照是否有名字,可分為有名字的命名空間、不能顯式定義的全域命名空間與匿名命名空間。後者的聲明為:
namespace {
// namespace-body(即声明序列(可选))
}
匿名命名空間中的名字具有檔案作用域。這些名字在本編譯單元中可以直接使用;也可以用字首為::
的qualified-id顯式限定後使用。匿名命名空間中的名字具有內部連結屬性。
命名空間的成員,是在命名空間體的花括號內聲明了的名字。可以在命名空間體之外,給出命名空間成員的定義。即命名空間的成員聲明與定義可以分開。命名空間內的名字,只能有一次定義,但可以多次聲明。
巢狀的子命名空間必須定義在上層命名空間體之內。禁止把子命名空間的聲明與定義分開。
不能以「命名空間名::成員名;」方式,在命名空間體之外為命名空間添加新成員。必須在命名空間體之中添加新成員的聲明。
可以多次聲明和定義同一命名空間,每次給這一命名空間添加新成員。同名的命名空間即便在聲明位置不同,仍然是同一個實體。
可以在一個命名空間中引入其他命名空間的成員。例如:
namespace myNameSpace{
using namespace His_NameSpace;
using OLib::List;
void my_func(String &, List &);
}
參照命名空間的成員,有下述辦法:
- 使用命名空間的作用域解析運算子
::
,如:std::cout
using namespace 命名空间名[::命名空间名…];
這稱為「using-Directive」。該陳述式使指定的命名空間中的目前已經聲明的名字都提升到當前陳述式所在的作用域中可直接使用。如果引入的名字與該陳述式所在的聲明區域的名字發生衝突,則編譯器並不會發出任何警告資訊,而只是用聲明區域中的名字自動隱藏(hiding)命名空間中的同名成員,即使using namespace
更靠後也是如此。using 命名空间名::[命名空间名::……]成员名;
這稱作「using-declaration」。用於向名字空間或者塊作用域內引入其它名字空間的名字成員;也可用於把基礎類別的非私有成員引入到衍生類別的定義中,如果引入的是基礎類別的多載函數名字,則把基礎類別的所有同名函數引入,如果衍生類別有同名同參數同限定的成員函數,則基礎類別的函數被名字隱藏或覆蓋。如果引入的名稱與局部名稱發生同名衝突,編譯器會報錯。
命名空間可以有別名:namespace 别名 = 命名空间名;
這使得名字較長的命名空間可以方便地用較短的別名來參照。
C++11起支援行內命名空間。使用inline namespace
作為聲明的起始。行內命名空間的名稱在名稱尋找時被特別對待,使用qualified-id參照其中的名稱時,被行內的命名空間名稱可以省略。也即,行內命名空間內的識別碼被提升到包含着行內的命名空間的那個父級的命名空間中。行內命名空間可以在修改命名空間名稱的同時避免在二進制檔案中生成的符號改變,因此不同行內命名空間的名稱可以用於標識介面相容的不同版本,有助於保持二進制相容性。這也在標準庫的實現中被使用,如libstdc++和libc++。
namespace Contoso
{
namespace v_10
{
template <typename T>
class Funcs
{
public:
Funcs(void);
T Add(T a, T b);
T Subtract(T a, T b);
T Multiply(T a, T b);
T Divide(T a, T b);
};
}
inline namespace v_20
{
template <typename T>
class Funcs
{
public:
Funcs(void);
T Add(T a, T b);
T Subtract(T a, T b);
T Multiply(T a, T b);
std::vector<double> Log(double);
T Accumulate(std::vector<T> nums);
};
}
}
在XML中的應用
XML雖然不是一個獨立的程式語言,但是它的出現使得命名空間的使用變得更為廣泛。
在同一個命名空間裏,所有的元素名都必須唯一。
聲明一個命名空間使用XML保留的屬性xmlns
,它的值必須是URI(統一資源標誌符 Uniform Resource Identifier而非URL--Universal Resource Locator)指代.比如xmlns="http://www.w3.org/1999/xhtml".注意,事實上URI是不可讀的,但它對XML解析器來說就只是簡單不過的字串,如http://www.w3.org/1999/xhtml/(頁面存檔備份,存於互聯網檔案館) 這個地址本身並不包含任何代碼,它只表示XHTML命名空間.使用URI (比如"http://www.w3.org/1999/xhtml")去標示一個命名空間,而不是用一個簡短的字串 (比如"xhtml"),這樣做是為了減少不同命名空間標示符衝突的可能性.
註釋
- ^ Adya, Atul; Bolosky, William; Castro, Miguel; Cermak, Gerald; Chaiken, Ronnie; Douceur, John; Howell, Jon; Lorch, Jacob; Theimer, Marvin; Wattenhofer, Roger. FARSITE: Federated, Available, and Reliable Storage for an Incompletely Trusted Environment (PDF). Proc. USENIX Symp. on Operating Systems Design and Implementation. 2002 [2021-02-11]. (原始內容 (PDF)存檔於2010-07-28).
The primary construct established by a file system is a hierarchical directory namespace, which is the logical repository for files.