當定義一個命名空間時,能夠忽略這個命名空間的名稱:html
今天獲得來自google的老大的指點,學習了一個新的用法:匿名命名空間。
C++另外有一種匿名的命名空間,來保證生成的符號是局部的,這樣對於匿名空間中的變量等,外部都是不可見的. //test3.cpp static void bar(){} namespace //匿名的命名空間 { float bar2; int foo; } //test4.cpp extern int foo; extern void bar(); extern float bar2; int main() { bar(); //外部的bar()被聲明爲static,這裏連接不到符號.不能訪問 bar2 = 0.1f; //外部的匿名空間哩,這裏也不能訪問. foo = 0xFF; return 0; };//若是將test4的目標和test3的目標進行連接,其實是找不到這些符號的.連接會失敗. 匿名的命名空間是C++的特性,相對於C的static聲明來講,能夠在匿名的空間裏面聲明不少變量和函數,這樣能夠省去了對每一個變量和函數添加static聲明. 實質上匿名空間的功能跟static聲明是同樣的.
對於一個大型的C語言軟件項目,給函數和全局變量起名不是一個容易的事情,由於必須考慮有沒有可能與其它程序員寫的代碼衝突,多數的作法是對每一個模塊的一組函數名加個特定前綴,如HTRequest_setInternal、HTRequest_internal等。這使得程序員每次調用這些函數時都必須多輸出一些字符,雖然使用如今比較優秀的IDE(Integrated Development Environment),不會給程序員的輸入帶來多少負責,但這些字符看起來仍是有些多餘。因此C++引入了namespace的概念,把一些標識符以命名空間樹結構的方式組織起來,使代碼看起來更優雅。並且事實證實,該特性是先進的,對於大型項目的做用是明顯的,而且在後來的編程語言如Java、C#、Python都支持此類特性,只是有些叫法不一樣而已。ios
命名空間不只能夠用於組織類型(class、struct、Enum)等,還能夠用於組織全局變量、全局函數等。如例程[2-1]所示,將不一樣模塊的標識符分別組織到不一樣的命名空間中,從而避免標識符的衝突。程序員
// 例程[2-1]編程
#include <iostream>瀏覽器
namespace sock{socket
typedef unsigned short socket_port_t;編程語言
const char* LOOPBACK_ADDR = 「127.0.0.1」;函數
const socket_port_t DEFUALT_HTTP_PORT = 80;學習
int main( void )
{
std::cout<<」Local HTTP addr = 「<<sock::LOOPBACK_ADDR
<<’:’<<sock::DEFUALT_HTTP_PORT<<std::endl;
return 0;
}
在大型的C++項目中使用命名空間比較好的項目如Google瀏覽器Chorme、開源C++庫boost等,而沒有使用命名空間的一個例子就是開源C++庫ACE(The ADAPTIVE Communication Environment ),它選擇了在每一個類型的前面加上前綴「ACE_」,使得標識符都比較長,並且看起來有點兒冗餘。爲使用起來方便,並且不修改ACE的源碼,可使用typedef標識符對這些標識符進行重命名,如例程[2-2]所示。請注意,不能在這裏使用#define,由於宏不受命名空間的限制。
// 例程[2-2]
#include <ace/Mutex.h>
namespace ace{
typedef ACE_Mutex Mutex;
typedef ACE_Lock Lock;
}
當引用的標識符不在當前命名空間或全局命名空間內時,有三種方式能夠引用該標識符,如引用前一節新定義的ace命令空間中的Mutex類型:
// 方式一
ace::Mutex mutex;
// 方式二
using ace::Mutex;
Mutex mutex;
// 方式三
using namespace ace;
Mutex mutex;
方式一隻在必要的時候經過域運算符「::」引用指定命令空間內的標識符,適用於當前編譯單元引用ace內的標識符很少,並且編譯單元內使用這些標識符的次數也很少的狀況。
方式二隻引入ace::Mutex一個標識符,若是在當前編譯單元內使用ace::Mutex次數較多,並且不會與當前命名空間內的標識符衝突,建議使用這種方式。
方式三是把ace命名空間中的所有標識符都引入到當前命名空間中,此後ace全部的標識符對於當前命名空間都是可見的,這會提升標識符衝突的危險。若是當前編譯單元用到ace命令空間內的標識符較多,並且不會出現標識符衝突的問題,可使用這種方式,以減小字符的輸入。
對於以上三種方式,建議優先選擇第一種,這種方式最不容易產生標識符衝突,方式二次之,儘量不用第三種試,即便是對於C++標準庫也不要使用第三種方式,由於至少在Solaris系統中就有一個struct類型叫map ??,若是你引用了包含該類型的頭文件就會致使命名衝突。
另外,建議不要在頭文件中使用using語句引入標識符,不然這些標識符將被暴露到引用這個頭文件的全部編譯單元內,這樣很容易使命名空間失去其做用而產生命名衝突。
對於用到的系統API,建議函數名前使用域運算符加以區別,使程序可讀性更好,如:::GetLastError( ), ::getcwd( )。
注意,切忌在自定義的命名空間中引用系統頭文件,如例程[2-3]所示,避免形成標識符的混亂。
// 例程[2-3]
namespace my_space{
#include <net/if.h>
}
當要引用的命名空間比較長,並且想用第一種方式引用命名空間內的實體,則能夠經過命名空間別名,爲原來的命名空間起個簡短的名字,如例程[2-4]。
// 例程[2-4]
namespace long_namespace{
void func( void ) { /* function body */ }
}
namespace ns = long_namespace;
int main( void )
{
ns::func();
return 0;
}
當聲明命名空間時的名稱爲空時,則該命名空間爲匿名命名空間(unnamed namespace)。匿名的空間是C++用於替代使用static定義做用域爲本編譯單元的全局函數或全局變量的一種新的替代方式,匿名空間與命名的命名空間同樣能夠嵌套。因爲匿名命名空間沒有命名空間的名字,因此也沒法在其它的編譯單元內經過extern聲明該變量,因而該變量天然也只在本編譯單元內可見,如例程[2-5]。
// 例程[2-5]
#include <iostream>
using namespace std;
namespace{ int i = 256; }
namespace ns{
namespace { int i = 128; }
void func(void)
{
cout<<"ns::func :" <<endl;
cout<<"\t::i="<<::i<<endl;
cout<<"\tns::i="<<i<<endl;
}
}
int main(void )
{
cout<<::i<<endl;
cout<<"i="<<i<<endl;
cout<<"ns::i="<<ns::i<<endl;
ns::func();
return 0;
}
使用匿名空間比使用static至少有兩個好處:
1) 對於一組多個標識符函數只須要使用一個匿名空間來聲明,不須要屢次輸入static。
2) 能夠嵌套。這樣能夠在不一樣命名空間中使用多個同名的標識符。
在C++的標準中也建議使用匿名命名空間間定義編譯單元內部的全局變量,替代static,static關鍵詞在此處被認爲是過時的(deprecated)特性。