C++ 命名空間namespace

本文轉(zhuǎn)載自:C++ 命名空間namespace

C++中灯荧,名稱(name)可以是符號常量礁击、變量、宏、函數(shù)哆窿、結(jié)構(gòu)链烈、枚舉、類和對象等等挚躯。為了避免强衡,在大規(guī)模程序的設(shè)計(jì)中,以及在程序員使用各種各樣的C++庫時码荔,這些標(biāo)識符的命名發(fā)生沖突漩勤,標(biāo)準(zhǔn)C++引入了關(guān)鍵字namespace(命名空間/名字空間/名稱空間/名域),可以更好地控制標(biāo)識符的作用域缩搅。

MFC中并沒有使用命名空間越败,但是在.NET框架、MC++C++/CLI中硼瓣,都大量使用了命名空間究飞。

作用域與命名空間

相關(guān)概念

與命名空間相關(guān)的概念有:

聲明域(declaration region)—— 聲明標(biāo)識符的區(qū)域。如在函數(shù)外面聲明的全局變量堂鲤,它的聲明域?yàn)槁暶魉诘奈募诟怠T诤瘮?shù)內(nèi)聲明的局部變量,它的聲明域?yàn)槁暶魉诘拇a塊(例如整個函數(shù)體或整個復(fù)合語句)筑累。

潛在作用域(potential scope)—— 從聲明點(diǎn)開始袱蜡,到聲明域的末尾的區(qū)域。因?yàn)镃++采用的是先聲明后使用的原則慢宗,所以在聲明點(diǎn)之前的聲明域中坪蚁,標(biāo)識符是不能用的。即镜沽,標(biāo)識符的潛在作用域敏晤,一般會小于其聲明域。

作用域(scope)—— 標(biāo)識符對程序可見的范圍缅茉。標(biāo)識符在其潛在作用域內(nèi)嘴脾,并非在任何地方都是可見的。例如蔬墩,局部變量可以屏蔽全局變量译打、嵌套層次中的內(nèi)層變量可以屏蔽外層變量,從而被屏蔽的全局或外層變量在其倍屏蔽的區(qū)域內(nèi)是不可見的拇颅。所以奏司,一個標(biāo)識符的作用域可能小于其潛在作用域。

命名空間

命名空間(namespace是一種描述邏輯分組的機(jī)制樟插,可以將按某些標(biāo)準(zhǔn)在邏輯上屬于同一個集團(tuán)的聲明放在同一個命名空間中韵洋。

原來C++標(biāo)識符的作用域分成三級:代碼塊({……}竿刁,如復(fù)合語句和函數(shù)體)、類和全局√掠В現(xiàn)在食拜,在其中的類和全局之間,標(biāo)準(zhǔn)C++又添加了命名空間這一個作用域級別副编。

命名空間可以是全局的负甸,也可以位于另一個命名空間之中,但是不能位于類和代碼塊中痹届。所以惑惶,在命名空間中聲明的名稱(標(biāo)識符),默認(rèn)具有外部鏈接特性(除非它引用了常量)短纵。

在所有命名空間之外,還存在一個全局命名空間僵控,它對應(yīng)于文件級的聲明域香到。因此,在命名空間機(jī)制中报破,原來的全局變量悠就,現(xiàn)在被認(rèn)為位于全局命名空間中。

標(biāo)準(zhǔn)C++庫(不包括標(biāo)準(zhǔn)C庫)中所包含的所有內(nèi)容(包括常量充易、變量梗脾、結(jié)構(gòu)、類和函數(shù)等)都被定義在命名空間std(standard標(biāo)準(zhǔn))中了盹靴。

定義命名空間

有兩種形式的命名空間——有名的和無名的炸茧。

命名空間的定義格式為:(取自C++標(biāo)準(zhǔn)文檔):

named-namespace-definition:

namespace identifier { namespace-body }

unnamed-namespace-definition:

 namespace { namespace-body }

namespace-body: declaration-seq optional

即:(自己翻譯并改寫的)

有名的命名空間:

       namespace 命名空間名 {

              聲明序列(可選)

       }

無名的命名空間:

       namespace {

              聲明序列(可選)

       }

命名空間的成員,是在命名空間定義中的花括號內(nèi)聲明了的名稱稿静∷蠊冢可以在命名空間的定義內(nèi),定義命名空間的成員(內(nèi)部定義)改备。也可以只在命名空間的定義內(nèi)聲明成員,而在命名空間的定義之外,定義命名空間的成員(外部定義)奶栖。

命名空間成員的外部定義的格式為:

命名空間名::成員名 ... ...

例如:

// out.h

namespace Outer { // 命名空間Outer的定義

    int i; // 命名空間Outer的成員i的內(nèi)部定義

    namespace Inner { // 子命名空間Inner的內(nèi)部定義
        void f() { i++; } // 命名空間Inner的成員f()的內(nèi)部定義棘捣,其中的i為Outer::i

        int i;

        void g() { i++; } // 命名空間Inner的成員g()的內(nèi)部定義,其中的i為Inner::i
        void h(); // 命名空間Inner的成員h()的聲明

    }

    void f(); // 命名空間Outer的成員f()的聲明

           // namespace Inner2; // 錯誤默勾,不能聲明子命名空間
}

void Outer::f() {i--; } // 命名空間Outer的成員f()的外部定義

void Outer::Inner::h() {i--; } // 命名空間Inner的成員h()的外部定義

// namespace Outer::Inner2 {/*... ...*/} // 錯誤碉渡,不能在外部定義子命名空間

注意

不能在命名空間的定義中聲明(另一個嵌套的)子命名空間,只能在命名空間的定義中定義子命名空間灾测。

也不能直接使用“命名空間名::成員名 ……”定義方式爆价,為命名空間添加新成員垦巴,而必須先在命名空間的定義中添加新成員的聲明。

另外铭段,命名空間是開放的骤宣,即可以隨時把新的成員名稱加入到已有的命名空間之中去。方法是序愚,多次聲明和定義同一命名空間憔披,每次添加自己的新成員和名稱。例如:

namespace A {

    int i;

    void f();

} // 現(xiàn)在A有成員i和f()

namespace A {

    int j;

    void g();

} // 現(xiàn)在A有成員i爸吮、f()芬膝、j和g()

還可以用多種方法,來組合現(xiàn)有的命名空間形娇,讓它們?yōu)槲宜妹趟@纾?/p>

namespace My_lib {

       using namespace His_string;

       using namespace Her_vector;

       using Your_list::List;

       void my_f(String &, List &);

}

... ...

using namespace My_lib;

... ...

Vector<String> vs[5];

List<int> li[10];

my_f(vs[2], li[5]);

使用命名空間

作用域解析運(yùn)算符(::

對命名空間中成員的引用,需要使用命名空間的作用域解析運(yùn)算符::桐早。例如:

// out1.cpp

#include "out.h"

#include <iostream>
// 這里癣缅,我想記錄一下:
// 前面在namesapce Outer里面定義了一些變量,比如說i哄酝,我想說的是友存,這些變量在項(xiàng)目中的每個文件中
// 都是可見的,我們要訪問這些變量的話陶衅,只需要攜帶namsepace限定屡立,比如說Outer::i
// 這也是c++優(yōu)于c的一個部分吧!c的某個文件的變量要全局可見的話搀军,要用extern關(guān)鍵字來限定膨俐,顯得
// 特別麻煩。

int main() {

    Outer::i = 0;

    Outer::f(); // Outer::i = -1;

    Outer::Inner::f(); // Outer::i = 0;

    Outer::Inner::i = 0;

    Outer::Inner::g(); // Inner::i = 1;

    Outer::Inner::h(); // Inner::i = 0;

    std::cout << "Hello, World!" << std::endl;

    std::cout << "Outer::i = " << Outer::i << ",  Inner::i = " << Outer::Inner::i << std::endl;
}

using指令(using namespace

為了省去每次調(diào)用Inner成員和標(biāo)準(zhǔn)庫的函數(shù)和對象時奕巍,都要添加Outer::Inner::std::的麻煩吟策,可以使用標(biāo)準(zhǔn)C++using編譯指令來簡化對命名空間中的名稱的使用。格式為:

using namespace 命名空間名[::命名空間名……];

在這條語句之后的止,就可以直接使用該命名空間中的標(biāo)識符檩坚,而不必寫前面的命名空間定位部分。因?yàn)?code>using指令诅福,使所指定的整個命名空間中的所有成員都直接可用匾委。例如:

// out2.cpp

#include "out.h"

#include <iostream>

// using namespace Outer; // 編譯錯誤,因?yàn)樽兞縤和函數(shù)f()有名稱沖突

using namespace Outer::Inner;

using namespace std;

int main() {

    Outer::i = 0;

    Outer::f(); // Outer::i = -1;

    f(); // Inner::f()氓润,Outer::i = 0;

    i = 0; // Inner::i

    g(); // Inner::g()赂乐,Inner::i = 1;

    h(); // Inner::h(),Inner::i = 0;

    cout << "Hello, World!" << endl;

    cout << "Outer::i = " << Outer::i << ",  Inner::i = " << i << endl;

}

又例如:(.NET框架)

using namespace System::Drawing::Imaging;

using namespace System::Window::Forms::Design::Behavior;

using聲明(using

除了可以使用using編譯指令(組合關(guān)鍵字using namespace)外咖气,還可以使用using聲明來簡化對命名空間中的名稱的使用挨措。格式為:

using 命名空間名::[命名空間名::……]成員名;

注意挖滤,關(guān)鍵字using后面并沒有跟關(guān)鍵字namespace,而且最后必須為命名空間的成員名(而在using編譯指令的最后浅役,必須為命名空間名)斩松。

using指令不同的是,using聲明只是把命名空間的特定成員的名稱觉既,添加該聲明所在的區(qū)域中惧盹,使得該成員可以不需要采用,(多級)命名空間的作用域解析運(yùn)算符來定位瞪讼,而直接被使用钧椰。但是該命名空間的其他成員,仍然需要作用域解析運(yùn)算符來定位符欠。例如:

// out3.cpp

#include "out.h"

#include <iostream>

using namespace Outer; // 注意嫡霞,此處無::Inner

using namespace std;

// using Inner::f; // 編譯錯誤,因?yàn)楹瘮?shù)f()有名稱沖突

using Inner::g; // 此處省去Outer::希柿,是因?yàn)镺uter已經(jīng)被前面的using指令作用過了
using Inner::h;

int main() {

    i = 0; // Outer::i

    f(); // Outer::f()秒际,Outer::i = -1;

    Inner::f(); // Outer::i = 0;

    Inner::i = 0;

    g(); // Inner::g(),Inner::i = 1;

    h(); // Inner::h()狡汉,Inner::i = 0;

    cout << "Hello, World!" << endl;

    cout << "Outer::i = " << i << ",  Inner::i = " << Inner::i << endl;

}

using指令與using聲明的比較

可見,using編譯指令和using聲明闽颇,都可以簡化對命名空間中名稱的訪問盾戴。

using指令使用后,可以一勞永逸兵多,對整個命名空間的所有成員都有效尖啡,非常方便。而using聲明剩膘,則必須對命名空間的不同成員名稱衅斩,一個一個地去聲明,非常麻煩怠褐。

但是畏梆,一般來說,使用using聲明會更安全奈懒。因?yàn)椋?code>using聲明只導(dǎo)入指定的名稱奠涌,如果該名稱與局部名稱發(fā)生沖突,編譯器會報(bào)錯磷杏。而using指令導(dǎo)入整個命名空間中的所有成員的名稱溜畅,包括那些可能根本用不到的名稱,如果其中有名稱與局部名稱發(fā)生沖突极祸,則編譯器并不會發(fā)出任何警告信息慈格,而只是用局部名去自動覆蓋命名空間中的同名成員怠晴。特別是命名空間的開放性,使得一個命名空間的成員浴捆,可能分散在多個地方蒜田,程序員難以準(zhǔn)確知道,別人到底為該命名空間添加了哪些名稱汤功。

雖然使用命名空間的方法物邑,有多種可供選擇。但是不能貪圖方便滔金,一味使用using 指令色解,這樣就完全背離了設(shè)計(jì)命名空間的初衷,也失去了命名空間應(yīng)該具有的防止名稱沖突的功能餐茵。

一般情況下科阎,對偶爾使用的命名空間成員,應(yīng)該使用命名空間的作用域解析運(yùn)算符來直接給名稱定位忿族。而對一個大命名空間中的經(jīng)常要使用的少數(shù)幾個成員锣笨,提倡使用using聲明,而不應(yīng)該使用using編譯指令道批。只有需要反復(fù)使用同一個命名空間的許多數(shù)成員時错英,使用using編譯指令,才被認(rèn)為是可取的隆豹。

例如椭岩,如果一個程序(如上面的outi.cpp)只使用一兩次cout,而且也不使用std命名空間中的其他成員璃赡,則可以使用命名空間的作用域解析運(yùn)算符來直接定位判哥。如:

#include <iostream>

... ...

std::cout << "Hello, World!" << std::endl;

std::cout << "Outer::i = " << Outer::i << ",  Inner::i = " << Outer::Inner::i << std::endl;

又例如,如果一個程序要反復(fù)使用std命名空間中的cin碉考、coutcerr(如上面的outi.cpp)塌计,而不怎么使用其他std命名空間中的其他成員,則應(yīng)該使用using 聲明而不是using指令侯谁。如:

#include <iostream>

... ...

using std::cout;

cout << "Hello, World!" << endl;

cout << "Outer::i = " << Outer::i << ",  Inner::i = " << Outer::Inner::i << endl;

命名空間的名稱

命名空間別名

標(biāo)準(zhǔn)C++引入命名空間锌仅,主要是為了避免成員的名稱沖突。若果用戶都給自己的命名空間取簡短的名稱墙贱,那么這些(往往同是全局級的)命名空間本身技扼,也可能發(fā)生名稱沖突。如果為了避免沖突嫩痰,而為命名空間取很長的名稱剿吻,則使用起來就會不方便。這是一個典型的兩難問題串纺。

標(biāo)準(zhǔn)C++為此提供了一種解決方案——命名空間別名丽旅,格式為:

namespace 別名 = 命名空間名;

例如:(AT&T美國電話電報(bào)公司)

namespace American_Telephone_and_Telegraph { // 命名空間名太長

       class String {

              String(const char*);

              // ... ...

       }

}

American_Telephone_and_Telegraph::String s1 // 使用不方便

= new American_Telephone_and_Telegraph::String("Grieg");

namespace ATT = American_Telephone_and_Telegraph; // 定義別名

ATT::String s2 = new ATT::String("Bush"); // 使用方便

ATT::String s3 = new ATT::String("Nielsen");

無名命名空間

標(biāo)準(zhǔn)C++引入命名空間椰棘,除了可以避免成員的名稱發(fā)生沖突之外,還可以使代碼保持局部性榄笙,從而保護(hù)代碼不被他人非法使用邪狞。如果你的目的主要是后者,而且又為替命名空間取一個好聽茅撞、有意義帆卓、且與別人的命名空間不重名的名稱而煩惱的話,標(biāo)準(zhǔn)C++還允許你定義一個無名命名空間米丘。你可以在當(dāng)前編譯單元中(無名命名空間之外)剑令,直接使用無名命名空間中的成員名稱,但是在當(dāng)前編譯單元之外拄查,它又是不可見的吁津。

無名命名空間的定義格式為:

namespace {

       聲明序列(可選)

}

實(shí)際上,上面的定義等價(jià)于:(標(biāo)準(zhǔn)C++中有一個隱含的使用指令)

namespace $$$ {

       聲明序列(可選)

}

using namespace $$$;

例如:

namespace {

       int i;

       void f() {/*... ...*/}

}

int main() {

       i = 0; // 可直接使用無名命名空間中的成員i

       f(); // 可直接使用無名命名空間中的成員f()

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末堕扶,一起剝皮案震驚了整個濱河市碍脏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌稍算,老刑警劉巖典尾,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異糊探,居然都是意外死亡急黎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門侧到,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人淤击,你說我怎么就攤上這事匠抗。” “怎么了污抬?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵汞贸,是天一觀的道長。 經(jīng)常有香客問我印机,道長矢腻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任射赛,我火速辦了婚禮多柑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘楣责。我一直安慰自己竣灌,他們只是感情好聂沙,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著初嘹,像睡著了一般及汉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屯烦,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天坷随,我揣著相機(jī)與錄音,去河邊找鬼驻龟。 笑死温眉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的迅脐。 我是一名探鬼主播芍殖,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谴蔑!你這毒婦竟也來了豌骏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤隐锭,失蹤者是張志新(化名)和其女友劉穎窃躲,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钦睡,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蒂窒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了荞怒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洒琢。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖褐桌,靈堂內(nèi)的尸體忽然破棺而出衰抑,到底是詐尸還是另有隱情,我是刑警寧澤荧嵌,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布呛踊,位于F島的核電站,受9級特大地震影響啦撮,放射性物質(zhì)發(fā)生泄漏谭网。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一赃春、第九天 我趴在偏房一處隱蔽的房頂上張望愉择。 院中可真熱鬧,春花似錦、人聲如沸薄辅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽站楚。三九已至脱惰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間窿春,已是汗流浹背拉一。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旧乞,地道東北人蔚润。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像尺栖,于是被迫代替她去往敵國和親嫡纠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容