C++中的作用域解析

字號:

名字空間域
    名字空間主要用于解決名字沖突的問題,在名字空間出現(xiàn)之前,庫的作者通常通過附加給庫中的類型,全局變量和函數(shù)予特定的前綴來防止名字沖突的問題,例如dbus庫的Error類型和Error初始化函數(shù)被命名為:
    DBusError
    dbus_init_error
    有了名字空間后,我們就可以通過附加名字空間的名字來構(gòu)成名字的限定名(Qualified Name)來解決名字沖突的問題。
    當然更主要的是我們可以通過名字空間別名,使用聲明(特定的名字)和使用指示(全部名字)來達成即能有效防止沖突,又能在已確定的上下文中更方便的訪問名字的作用。
    跟Java的包機制不同,名字空間是純邏輯上的,它不具備對文件組織上任何的物理約束,一個名字空間可以跨越多個編譯單元(常見的方式,一個庫一個名字空間),但也可以一個編譯單元包含多個名字空間(比較少見,通常是用來通過嵌套的子名字空間來防止一些函數(shù)重載上的意外發(fā)生)。(Java中的包,編譯單元,類型域的包含關(guān)系更加明確,容易理解和使用,一個包必然包含一個或多個編譯單元,一個編譯單元也必然包括一個或多個類型,而且只能有一個是包可見的——公共類)
    有的意見認為,名字空間引起的問題比它解決的要多,比如連接時名字解析的問題,特別是不同編譯器編譯出來的程序片段(靜態(tài)庫,導入庫,Object文件)如何能夠正確的連接。名字空間也使得重載的決議規(guī)則變的更復雜。所以像有些的庫仍然堅持使用前綴的方式,比如QT。
    名字空間出現(xiàn)后,以前的全局域就變成了名字空間的一個特例——全局名字空間。沒有放置在某個名字空間的類型,具有編譯單元外部鏈接的非成員函數(shù)和變量就缺省屬于全局名字空間。
    編譯單元域
    編譯單元域是個比較特殊的域,它通常跟代碼的物理組織方式有關(guān)。一個編譯單元中非成員變量和函數(shù)的名字可以有外部鏈接,從而使得鏈接器可以用來解決跨編譯單元的名字引用的問題(跨編譯單元的變量的名字引用通常被視為是邪惡的東西)。但是也可以沒有外部鏈接,從而防止一些無意中產(chǎn)生的副作用(錯誤的引用了不是預想中的名字)。
    沒有外部鏈接的名字處于編譯單元域,這個可以通過附加static修飾符來達成。例如:
    static double static_d = 3.0;
    Examda提示: 也可以放置在一個特殊的名字空間里,這個名字空間叫做匿名名字空間,每個編譯單元都可以有一個匿名名字空間,不同編譯單元之間的匿名名字空間不會相互影響,處于匿名名字空間的名字只能被該編譯單元所訪問。例如:
    namespace
    {
    double intern_d = 2.0;
    }
    namespace foo
    {
    static double static_d = 3.0;
    Foo::Foo(void)
    {
    intern_d = 3.0;
    }
    Foo::~Foo(void)
    {
    }
    }
    像上面的非成員變量intern_d就是處于編譯單元foo(foo.cpp)的匿名名字空間中。如果在頭文件中試圖導出這個變量,例如:
    extern double intern_d;
    實際上你會得到一個“ambiguous symbol”的編譯錯誤(在VC 2008中)。
    類型域
    用戶使用struct和class定義一個自定義類型,也同時構(gòu)成了一個類型域,處于類型域里面的變量和函數(shù)被稱為成員變量和成員函數(shù),它們可以是靜態(tài)的(屬于類型),也可以是非靜態(tài)的(屬于實例)。靜態(tài)的成員變量和成員函數(shù)與非成員變量和函數(shù)類似,而類型在這里只是起到一個特殊的名字空間的作用,或者說是附加類型成員訪問規(guī)則的名字空間,公共的靜態(tài)成員函數(shù)如果是可見的,那也是可訪問的,也就是具備外部鏈接。
    函數(shù)域
    每個函數(shù)都構(gòu)成了一個函數(shù)域,函數(shù)域的概念跟變量的存儲位置和生命期有關(guān)。函數(shù)的參數(shù)和在函數(shù)中聲明并定義的變量被稱為局部變量或者是自動變量,它們分配在堆棧上,它們隨著函數(shù)的執(zhí)行而生成,隨著函數(shù)的退出而消亡。而靜態(tài)成員變量和非成員變量則分配在靜態(tài)存儲區(qū)中,它們的位置是固定的,生命期從程序啟動一直到程序關(guān)閉。(在自由存儲區(qū)中動態(tài)分配的對象是由使用者來控制其生命周期的。)
    函數(shù)里面還可以有多個局部域,比如說每個if,else,else if,for,while,do,switch,try,catch塊,或者是用戶自己產(chǎn)生的代碼塊(使用{}包圍)。局部域的作用通常是用來進一步限制局部變量的使用范圍,在某個局部域聲明的局部變量,在退出該局部域時會被自動銷毀。用戶自己產(chǎn)生的代碼塊(局部域)多用于所謂的關(guān)鍵區(qū),用來同步線程對外部狀態(tài)的訪問。如果函數(shù)需要寫的很長,刻意的區(qū)分不同的局部域也有助于代碼的可讀性和防止不必要的錯誤。