namespace
用來建立名稱空間,或者開啟既存的名稱空間,因此,若想在其他標頭檔或原始碼位置,往〈簡介名稱空間〉中既有的 bank
名稱空間添加新的定義,只要指定相同名稱就可以了。例如:
namespace bank {
int x;
namespace vip {
class Foo {
...
};
int x;
}
...
}
名稱空間可以形成巢狀,以上例來說,想使用 Foo
類別的話,必須使用 bank::vip::Foo
,各個名稱空間中可以定義自身範疇中的名稱,內部名稱空間可以看得到外部名稱空間的名稱,然而外部名稱空間看不到內部定義的名稱,如果內部定義了與外部同名的名稱,那內部中的名稱會遮蔽外部的同名名稱。
如果標頭檔 a.h 定義了名稱空間為 na
,而它被 include
到另一名稱空間中:
namespace nb {
#include "a.h"
...
}
那麼 na
會成為 nb
內部的名稱空間,因此定義在 na
中的名稱,必須使用 nb::na
指定範疇來存取。
名稱空間可以 inline
,就好比展開在相對應的位置,例如,如果標頭檔 bankv1.h 定義了 inline
名稱空間為 bankv1
:
inline namespace bankv1 {
Account {
...
};
...
}
而它被 include
到另一名稱空間中:
namespace bank {
#include "bankv1.h"
...
}
那麼 bank
不會是 bank
的內部名稱空間,而會像是:
namespace bank {
Account {
...
};
...
}
其作用之一就在於,如果哪天定義了 bankv2
,定義在 bankv2.h:
inline namespace bankv2 {
Account {
...
};
...
}
那麼原本的 bankv1.h 可以去除 inline
:
namespace bankv1 {
Account {
...
};
...
}
若 bank
名稱空間修改為:
namespace bank {
#include "bankv2.h"
#include "bankv1.h"
...
}
那麼程式中使用到 bank::Account
的程式碼,會是 bankv2.h 定義的版本,如果基於相容性,還想繼續使用 bankv1.h 的定義,可以透過 bank::bankv1
指定範疇來存取。
namespace
也可用來為既有的名稱空間取別名,例如,為 bank::vip
取個 vip
的別名:
namespace vip = bank::vip;
名稱空間可以是匿名的,例如,若有個 foo.cpp 實作如下:
namespace {
int x = 10;
}
void foo() {
std::cout << x << std::endl;
}
...
匿名的名稱空間中定義的名稱,具有 static
的生命週期,在第一次使用到的時候被建立,程式結束之後銷毀,因為沒有名稱,只有與匿名空間同檔案、同層次的程式碼,可以直接存取匿名空間中的名稱,以上例來說,foo
與匿名空間都是定義於全域名稱空間,foo
中可以直接存取 x
。
然而,如果有另一個 foo2.cpp 也如下定義了 x
:
namespace {
int x = 10;
}
void foo2() {
std::cout << x << std::endl;
}
...
因為只有與匿名空間同檔案、同層次的程式碼,可以直接存取匿名空間中的名稱,x
僅在 foo2.cpp 中可見,若同時使用到 foo.cpp、foo2.cpp,編譯時並不會發生錯誤,然而拿掉匿名的 namespace
定義,就會因 x
重複定義而編譯錯誤。
只有與匿名空間同檔案、同層次的程式碼,可以直接存取匿名空間中的名稱,因此如果是以下:
namespace bank {
namespace {
int x = 10;
}
}
x
就只有同檔案、同樣在 bank
名稱空間的程式碼,才可以直接存取 x
,若是同檔案、非同一名稱空間的程式碼,必須透過 bank::x
來存取。