第三章命名規則比較著名的命名規則當推Microsoft公司的“匈牙利”法,該命名規則的主要思想是“在變數和函數名中加入首碼以增進人們對程式的理解”。例如所有的字元變數均以ch為首碼,若是整型數則用n為首碼。例如nWidth, chText, fTax. 但筆者認為這種表示方法過於煩瑣,而且未必真能有效增進理解,因此不建議用匈牙利法。良好的命名規則可便於記憶和理解。但是什麼是好的命名規則並沒有一個標準,程式員之間也很難達成意見一致,在同一個項目組中相對做到統一就可以了。
【規則3-1-1
】標識符應當直觀且可以拼讀,可望文知意,不必進行“解碼”。標識符最好採用英文單詞或其組合,便於記憶和閱讀。切忌使用漢語拼音來命名。程式中的英文單詞一般不會太複雜,用詞應當準確。例如不要把CurrentValue寫成NowValue。
【規則3-1-2
】標識符應該用最少的字元表達最準確的意思。迴圈變數可以用i, j, k這些變數。利用一些很明了常用的縮寫減小長度,如tmp(temp), flg(flag), cur(current),val(value),message(msg)
| char *pText; BOOL bSaved; int strLen // string length CRect curRect // current rectangle string msg //message |
【規則3-1-3
】命名規則盡量與所採用的作業系統或開發工具的風格保持一致。例如Windows應用程式的標識符通常採用“大小寫”混排的方式,如AddChild。而Unix應用程式的標識符通常採用“小寫加底線”的方式,如add_child。別把這兩類風格混在一起用。這裡建議用”大小寫”混排, 即使要使用底線_,底線數量不能多於一個。
【規則3-1-4
】程式中不要出現標識符完全相同的局部變數和全域變數,儘管兩者的範圍不同而不會發生語法錯誤,但會使人誤解。另外不要用大小寫不同區分兩個變數。
【規則3-1-5
】變數的名字應當使用“名詞”或者“形容詞+名詞”。
| float value;float oldValue;float newValue; |
【規則3-1-6
】全域函數的名字應當使用“動詞”或者“動詞+名詞”(動賓片語)。類的成員函數若賓語為對象本身,可省略賓語
| DrawBox(); // 全域函數 box->Draw(); // 類的成員函數 |
【規則3-1-7
】用正確的反義片語命名具有互斥意義的變數或相反動作的函數等。
| int minValue;int maxValue; int SetValue(…);int GetValue(…); |
【建議】多動腦筋想一個好的命名,不要偷懶。盡量避免名字中出現數字編號,如Value1,Value2等,除非邏輯上的確需要編號。
【規則3-1-8
】類名和函數名用大寫字母開頭的單片語合而成; 變數和參數用小寫字母開頭的單片語合而成,單詞之間用大寫開頭便於分割; 常量全用大寫的字母,必要時用底線分割單詞。
| class CNode; // 類名 class CLeafNode; // 類名 void DrawBox(void); // 函數名 void SetValue(int value); // 函數名 int drawMode; string oldText |
【規則3-1-9
】靜態變數加首碼s_(表示static)。如果不得已需要全域變數,則使全域變數加首碼g_(表示global),在指標變數前加一個p, 在布爾類型前加一個b.
| static double s_taxRate; CPen *pOldPen; bool bSaved;int g_howMuchMoney; // 全域變數 |
【規則3-1-10
】類開頭可以考慮用大寫C標註。類的資料成員加首碼m_(表示member),這樣可以避免資料成員與成員函數的參數同名。
| void Object::SetValue(int width, int height){ m_width = width;m_height = height;} |
【規則3-1-11
】為了防止某一軟體庫中的一些標識符和其它軟體庫中的衝突,可以為各種標識符加上能反映軟體性質的首碼。例如三維圖形標準OpenGL的所有庫函數均以gl開頭,所有常量(或宏定義)均以GL開頭。
| 結構體 MGAXIS, MGLINESTYLE, MGPLOT // GM首碼: MathGraph |
第四章運算式與語句
【規則4-1-1
】如果程式碼中的運算子比較多,用括弧確定運算式的操作順序,避免使用預設的優先順序。這樣比較明了,畢竟不是每個人都記得牢優先順序。
【規則4-1-2
】判斷布爾值的表達
| if (flag) // 表示flag為真if (!flag) // 表示flag為假 |
【規則4-1-3
】數值與0值的比較。將整型變數用“==”或“!=”直接與0比較,但不可將浮點變數用“==”或“!=”與任何數字比較。 千萬要留意,無論是float還是double類型的變數,都有精度限制。所以一定要避免將浮點變數用“==”或“!=”與數字比較,應該設法轉化成“>=”或“<=”形式。
| if (nValue == 0) //nValue為整型if (nValue != 0) |
| if ((x>=-EPSINON) && (x<=EPSINON))//其中EPSINON是允許的誤差(即精度)。 |
【規則4-1-4
】應當將指標變數用“==”或“!=”與NULL比較,表示待比較的是個指標。建議把NULL前置,避免錯用指派陳述式把NULL賦值給指標
| if (NULL == pDC) // 防止if ( pDC = NULL) |
【規則4-1-5
】不要在for 迴圈體內修改迴圈變數,防止for 迴圈失去控制。
【建議】建議for語句的迴圈控制變數的取值採用“半開半閉區間”寫法(由於數組索引從0開始)。x值屬於半開半閉區間“0 =< x < N”,起點到終點的間隔為N,迴圈次數為N。if(i=0;i<N;i++)
【規則4-1-6
】每個case語句的結尾不要忘了加break,否則將導致多個分支重疊(除非有意使多個分支重疊)。在case末尾最好加上default分支。每個case分支盡量不要超過20個語句。
【規則4-1-7
】在C++ 程式中只使用const常量而不使用宏常量,即const常量完全取代宏常量。在類裡面的常量用枚舉類型。常量全部用大寫字母
| const double PI = 3.1415926 |
| class A {… enum { SIZE1 = 100, SIZE2 = 200}; // 枚舉常量 int array1[SIZE1]; int array2[SIZE2]; }; |
【規則4-1-8
】define語句中的變數值必須加上完備的括弧, 減少錯誤可能
| #define MAX(a,b) ((a) > (b) ? (a) : (b)) |
第五章函數設計
【規則5-1-1
】參數的書寫要完整,不要貪圖省事唯寫參數的類型而省略參數名字。
【規則5-1-2
】參數命名要恰當,順序要合理。如果參數是指標,且僅作輸入用,則應在類型前加const,以防止該指標在函數體內被意外修改。例如編寫字串拷貝函數StringCopy,它有兩個參數。如果把參數名字起為str1和str2,例如
| void StringCopy(char *str1, char *str2); //不良的命名應為 void StringCopy(char *Dest, const char *Src); |
【規則5-1-3
】如果輸入參數以值傳遞的方式傳遞複雜物件,則宜改用“const &”方式來傳遞,這樣可以省去臨時對象的構造和析構過程,從而提高效率。
【建議】避免函數有太多的參數,參數個數盡量控制在5個以內。如果參數太多,在使用時容易將參數類型或順序搞錯。可以把幾個參數合并成一個結構。
【規則5-1-4
】在函數體的“入口處”,對參數的有效性進行檢查。很多程式錯誤是由非法參數引起的,我們應該充分理解並正確使用“斷言”(assert)來防止此類錯誤。還要檢查通過其它途徑進入函數體內的變數的有效性,例如全域變數、檔案控制代碼等。
【建議】函數的功能要單一,不要設計多用途的函數。
【建議】函數體的規模要小,盡量控制在100行代碼之內。
【建議】在函數內部產生的臨時堆記憶體塊和一些對象關聯,一般在函數的末尾刪除,以方便檢查。
| void Func(){ int *pTemp = new int[50]; ..... delete[] pTemp;} |