在C++中,名稱(name)可以是符號常量、變量、宏、函數、結構、枚舉、類和對象等等。為了避免在大規模程序的設計中,以及在程序員使用各種各樣的C++庫時,這些標識符的命名發生沖突,標準C++引入了關鍵字namespace(命名空間),可以更好地控制標識符的作用域。(MFC中并沒有使用命名空間,但是在.NET框架、MC++和C++/CLI中,都大量使用了命名空間。)
C語言標識符有局部(代碼塊{…},如復合語句和函數體)和全局兩種作用域,C++在這二者之間引入了類作用域(如類變量和成員函數)。標準C++又在類和全局之間,新添加了命名空間這一個作用域級別。
命名空間是一種描述邏輯分組的機制,可以將按某些標準在邏輯上屬于同一個集團的聲明放在同一個命名空間中。命名空間可以是全局的,也可以位于另一個命名空間之中,但是不能位于類和代碼塊中。所以,在命名空間中聲明的名稱(標識符),默認具有外部鏈接特性(除非它引用了常量)。在所有命名空間之外,還存在一個全局命名空間,它對應于文件級的聲明域。因此,在命名空間機制中,原來的全局變量,現在被認為位于全局命名空間中。
標準C++庫(不包括標準C庫)中所包含的所有內容(包括常量、變量、結構、類和函數等)都被定義在命名空間std(standard,標準)中了。
1)定義命名空間
有兩種形式的命名空間——有名的和無名的,它們的定義方法分別為:
namespace 命名空間名 { // 有名命名空間
[聲明序列]
}
namespace { // 無名命名空間
[聲明序列]
}
命名空間的成員,是在命名空間定義中的花括號內聲明了的名稱。可以在命名空間的定義內,定義命名空間的成員(內部定義)。也可以只在命名空間的定義內聲明成員,而在命名空間的定義之外,定義命名空間的成員(外部定義)。
命名空間成員的外部定義的格式為:
命名空間名::成員名 ……
注意:不能在命名空間的定義中聲明(另一個嵌套的)子命名空間,只能在命名空間的定義中定義子命名空間。也不能直接使用“命名空間名::成員名 ……”定義方式,為命名空間添加新成員,而必須先在命名空間的定義中添加新成員的聲明。另外,命名空間是開放的,即可以隨時把新的成員名稱加入到已有的命名空間之中去。方法是,多次聲明和定義同一命名空間,每次添加自己的新成員和名稱。例如:
namespace A { int i; void f(); } // 現在A有成員i和f()
namespace A { int j; void g(); } // 現在A有成員i、f()、j和g()
2)使用命名空間
使用命名空間的方法有三種:
A、作用域解析運算符(::)
對命名空間中成員的引用,需要使用命名空間的作用域解析運算符::。例如:
std::cout << "Hello, World!" << std::endl;
B、using指令(using namespace)
為了省去每次調用命名空間成員和標準庫的函數和對象時,都要添加“命名空間名::”和“std::”的麻煩,可以使用標準C++的using編譯指令來簡化對命名空間中的名稱的使用。格式為:
using namespace 命名空間名[::子命名空間名……];
在這條語句之后,就可以直接使用該命名空間中的標識符,而不必寫前面的命名空間定位部分。因為using指令,使所指定的整個命名空間中的所有成員都直接可用。例如:
using namespace std;
cout << "Hello, World!" << endl;
又例如(.NET框架):
using namespace System::Drawing::Imaging;
using namespace System::Window::Forms::Design::Behavior;
C、using聲明(using)
除了可以使用using編譯指令(組合關鍵字using namespace)外,還可以使用using聲明來簡化對命名空間中的名稱的使用。格式為:
using 命名空間名::[命名空間名::……]成員名;
注意,關鍵字using后面并沒有跟關鍵字namespace,而且最后必須為命名空間的成員名(而在using編譯指令的最后,必須為命名空間名)。
與using指令不同的是,using聲明只是把命名空間的特定成員的名稱,添加該聲明所在的區域中,使得該成員可以不需要采用,(多級)命名空間的作用域解析運算符來定位,而直接被使用。但是該命名空間的其他成員,仍然需要作用域解析運算符來定位。例如:
using std::cout;
cout << "Hello, World!" << std::endl;
D、using指令與using聲明的比較
可見,using編譯指令和using聲明,都可以簡化對命名空間中名稱的訪問。
using指令使用后,可以一勞永逸,對整個命名空間的所有成員都有效,非常方便。而using聲明,則必須對命名空間的不同成員名稱,一個一個地去聲明,非常麻煩。
但是,一般來說,使用using聲明會更安全。因為,using聲明只導入指定的名稱,如果該名稱與局部名稱發生沖突,編譯器會報錯。而using指令導入整個命名空間中的所有成員的名稱,包括那些可能根本用不到的名稱,如果其中有名稱與局部名稱發生沖突,則編譯器并不會發出任何警告信息,而只是用局部名去自動覆蓋命名空間中的同名成員。特別是命名空間的開放性,使得一個命名空間的成員,可能分散在多個地方,程序員難以準確知道,別人到底為該命名空間添加了哪些名稱。
雖然使用命名空間的方法,有多種可供選擇。但是不能貪圖方便,一味使用using 指令,這樣就完全背離了設計命名空間的初衷,也失去了命名空間應該具有的防止名稱沖突的功能。
一般情況下,對偶爾使用的命名空間成員,應該使用命名空間的作用域解析運算符來直接給名稱定位。而對一個大命名空間中的經常要使用的少數幾個成員,提倡使用using聲明,而不應該使用using編譯指令。只有需要反復使用同一個命名空間的許多數成員時,使用using編譯指令,才被認為是可取的。
新聞熱點
疑難解答