C 作用域使用規範建議

2021-07-09 15:38:37 字數 2867 閱讀 5866

c++ 在 c 的基礎上引入了名字空間機制,使c中作用域的級別從原有的檔案域(全域性作用域)、函式作用域和**塊作用域(區域性域)增加了名字空間域和類域。名字空間是ansi c++引入的可以由使用者命名的作用域,用來處理程式中常見的同名衝突。

**優點:**命名空間提供了(可巢狀)命名軸線(name axis,注:將命名分割在丌同命名空間內),當然,類也提供了(可巢狀)的命名軸線(注:將命名分割在丌同類的作用域內)。

**缺點:**命名空間具有迷惑性,因為它們和類一樣提供了額外的(可巢狀的)命名軸線。在標頭檔案中使用不具名的空間(匿名名字空間)容易違背c++的唯一定義原則(one definition rule (odr))。

// .cpp檔案中 

namespace

; // 經常使用的符號

bool ateof() // 使用本命名空間內的符號eof

} // namespace

匿名名字空間結束時用注釋// namespace標識。

使用匿名名字空間的作用主要是將匿名名字空間中的成員的作用域限制在原始檔中,其作用域與使用static關鍵字類似,但是與static關鍵字不同的是:包含在匿名名字空間中的成員(變數或者函式)具有外部連線特性,而用static修飾的變數或者函式具有內部連線特性,不能用來例項化模板的非型別引數。參考如下**:

#include using namespace std;

template class example

此程式無法通過編譯,因為靜態變數c不具有外部連線特性,因此不是真正的「全域性」變數。而類模板的非型別引數要求是編譯時常量表示式,或者是指標型別的引數要求指標指向的物件具有外部連線性。同樣是上面的這個程式,將char c=』a』;至於匿名空間進行定義,即可通過編譯並執行。讀者可自行考證。

(2)最好不要使用using指示符來引用名字空間

使用using指示符實際上就是取消了名字空間的保護作用,增加了命名衝突的概率。考察如下程式:

#include using std::cout;

using std::endl;

namespace foo

int a=2;

int main()

)限定其作用域。

在乙個類體中定義的類叫作巢狀類,也叫成員類(member class)。擁有巢狀類的類叫外圍類,有些地方也叫被巢狀類。

class foo

; };

優點:當巢狀(成員)類只在被巢狀類(enclosing class)中使用時很有用,將其置於被巢狀類作用域作為被巢狀類的成員不會汙染其他作用域同名類。可在被巢狀類中前置宣告巢狀類,在.cpp檔案中定義巢狀類,避免在被巢狀類中包含巢狀類的定義,因為巢狀類的定義通常只與實現相關。

缺點:只能在被巢狀類的定義中才能前置宣告巢狀類。因此,任何使用foo::bar*值針的標頭檔案必須包含整個foo的宣告。

規範:不要將巢狀類定義為public,除非它們是介面的一部分,比如,某方法使用了這個類的一系列選項。

(1)將區域性變數盡可能置於最小作用域內,在定義時將其顯示初始化

c++允許在函式的任何位置宣告和定義變數,我們提倡在盡可能小的作用域中定義變數,離第一次使用的位置越近越好,使得**易於閱讀、易於定位變數的定義位置、變數型別和初始值。特別的,在定義變數時應顯示的初始化。

int i; 

i = f(); // 壞——初始化和宣告分離

int i = g(); // 好——初始化時宣告

(2)構造資料型別的變數盡可能放在迴圈體外定義

如果變數是乙個物件,每次進入作用域都要呼叫其建構函式,每次退出作用域都要呼叫其析構函式。

// 低效的實現

for (int i = 0; i < 1000000; ++i)

類似以下變數f放到迴圈作用域外面宣告要高效的多:

foo f; //建構函式和析極函式只呼叫1次

for(int i = 0; i < 1000000; ++i)

(1)盡量不要定義構造型別的全域性變數

構造型別的全域性變數,如類物件的建構函式、析構函式以及初始化操作的呼叫順序只是被部分規定,每次生成有可能會有髮化,從而導致難以發現的bugs。

因此,應禁止使用class型別的全域性變數(包括stl的string, vector等等),因為它們的初始化順序有可能導致構造出現問題。內建型別和由內建型別構成的沒有建構函式的結構體可以使用,如果一定要使用class型別的全域性變數,請使用單件模式(singleton pattern)。

(2)對於全域性的字串常量,使用c風格的字串,而不要使用stl的字串

const char kfrogsays = "ribbet";
雖然允許在全域性作用域中使用全域性髮量,使用時務必三思。大多數全域性變數應該是類的靜態資料成員,或者當其只在.cpp檔案中使用時,將其定義到不具名名字空間中,或者使用靜態關聯以限制變數的作用域。

記住,靜態成員變數視為作用域限制在類域的全域性變數,所以,也不能是class型別!

(1)cpp原始檔中的匿名名字空間可避免命名衝突、限定作用域,避免直接使用using指示符汙染命名空間;

(2)巢狀類符合區域性使用原則,只是不能在其他標頭檔案中前置定義,盡量不要設為public;

(3)盡量不用全域性函式和全域性變數,考慮作用域和命名空間限制,盡量單獨形成編譯單元;

(4)多執行緒中的全域性變數(含靜態成員變數)不要使用class型別(含stl容器),避免不明確行為導致的bugs。

作用域的使用,除了考慮名稱汙染、可讀性之外,主要是為降低耦合度、提高編譯和執行效率。

[1] c++名字空間詳解

[2] c++的作用域與生命週期

Context作用 型別 使用建議

是乙個訪問系統資源和進行應用程式級操作的抽象介面,稱為上下文 textview tv new textview getcontext audiomanager am audiomanager getcontext getsystemservice context.audio service getc...

c語言塊級作用域 C語言 作用域

c語言 作用域 型別作用域 生命週期 auto變數 一對 內 當前函式 static區域性變數 一對 內 整個程式執行期 extern變數 整個程式 整個程式執行期 static全域性變數 當前檔案 整個程式執行期 extern函式 整個程式 整個程式執行期 static函式 當前檔案 整個程式執行...

USB 讀 RAM buffer 使用規範建議

questions 硬體和軟體同時去訪問 usb ram buffer 造成資料亂掉或丟失 造成亂碼流程 1,軟體設定 usb valid 2,關總中斷,usb 收資料到 ram buffer,此時 usb 為 nak 3,usb 中斷不能及時響應,此時軟體再次將 usb 置 valid,開總中斷 ...