10. 編碼規範
“編碼風格應該儘可能地合理、簡潔”
10.1. 書寫風格
√ 要求類的書寫風格如下:
//單繼承,寫成一行
classs ClassName : public BaseClassName //多重繼承,寫成多行classs ClassName : public BaseClassName1,public BaseClassName2 { public: //////////////////////////////////////////////////////////////////////////////// //ctor & dtor ClassName(); virtual ~ ClassName(); public: //////////////////////////////////////////////////////////////////////////////// //public overrides,from BaseClassName1 virtual void Func1_1(); //////////////////////////////////////////////////////////////////////////////// //public overrides,from BaseClassName2 virtual void Func2_1(); //////////////////////////////////////////////////////////////////////////////// //public virtual method virtual void Func3_1(); //////////////////////////////////////////////////////////////////////////////// //public methods void Func1(); protected://////////////////////////////////////////////////////////////////////////////// // protected overrides,from BaseClassName1 virtual void Func1_1(); //////////////////////////////////////////////////////////////////////////////// // protected overrides,from BaseClassName2 virtual void Func2_1(); //////////////////////////////////////////////////////////////////////////////// // protected virtual method virtual void Func3_1(); //////////////////////////////////////////////////////////////////////////////// // protected methods void Func1(); private: //////////////////////////////////////////////////////////////////////////////// // private methods void Func1(); //////////////////////////////////////////////////////////////////////////////// // private Fields type m_field1;type m_field2; }
√ 要求將花括弧單獨寫在一行。 //不好 if(DoSomething()){ … } //不好 if(DoSomething()){…} //好if(DoSomething()){ … }
√ 要求if、for、do、while、case、switch、default等語句自佔一行,且if、for、do、while等語句的執行語句部分無論多少都要加括弧{}
√ 要求程式塊要採用縮排風格編寫,縮排的空格數為4個。
√ 要求相對獨立的程式塊之間、變數說明之後必須加空行。
×
不要把多個短語句寫在一行中,即一行唯寫一條語句。
√ 要求較長的語句(>80字元)要分成多行書寫。
√ 要求迴圈、判斷等語句中若有較長的運算式或語句,則要進行適應的劃分,長運算式要在低優先順序操作符處劃分新行,操作符放在新行之首。
例如,if ((taskNo < MAXTASKNUMBER) && (taskNo>0)) { … }例如,//不好rect.Length = 0; rect.Width = 0;//好rect. Length = 0; rect. Width = 0; √ 要求注意運算子的優先順序,並用括弧明確運算式的操作順序,避免使用預設優先順序。例如,//不好high << 8 | lowa | b && a & ca | b < c & d//好word = (high << 8) | low if ((a | b) && (a & c))if ((a | b) < (c & d))
√ 要求在形式參數之間的逗號後添加空格。void Foo(char bar,int x,int y);//不好 void Foo(char bar, int x, int y);//好l
推薦不要在實際參數之間添加空格。 Foo( MyChar,0,1 );//不好Foo(MyChar,0,1);//好
×
不要在函數和’(‘之間添加空格。Foo ();//不好 Foo();//好
×
不要在’[‘之後和’]’之前添加空格。X = dataArray[ index ];//不好 X = dataArray[index];//不好l
推薦在二元操作符之前或之後添加空格。 if(x==y)// 不好 // 好if(x == y) a = 0;a = b;a >>= 2;a = b ^ 2;
×
不要在一元操作符之前或之後添加空格。if(! x)//不好// 好 if(!x)//好if (a->b) *p = 'a';flag = !isEmpty;10.1.1. 模板書寫風格
√ 要求模板函數/類的泛型型別的關鍵字使用typename,不要使用class。
//不好 template<class T> inline Max(const T& x1, const T& x2)
//好 template<typename T> inline Max(const T& x1, const T& x2)
√ 要求模板函數/類的書寫風格如下: template<typename T> class MyTemplate{ void Method1(); template<typename TParam> void Method2(const TParam& param);}template<typename T> inline Max(const T& x1, const T& x2)
10.2. 注釋l
推薦不要在代碼實現中添加註釋。
例外:說明某個複雜的演算法
√ 要求為
向外部模組
/
包暴露的介面、類、函數、變數等添加註釋。
更多的注釋方法請參考
附錄B。
例如, //! Call native method extern void CallNativeMethod(); /*! /interface IExporter For the usage of exporting the file to PDF/PS/XML etc. */ interface IExporter { … } /*! /class Exporter For the usage of exporting the file to PDF/PS/XML etc. */ class Exporter : public IExporter { … }
10.3. 標識符命名
√ 要求遵守命名規範。
10.4. 編碼風格10.4.1. 常量
×
不要使用魔數(Magic Number) 。
√ 要求常量的命名全部使用大寫。 例如, const int MaxPath = 256;//不好const int Max_Path = 256;//不好const int maxpath = 256;//不好 const int MAXPATH = 256;//好
×
不要使用#define而是使用const來定義常量。 例如, #define MAXPATH 256//不好 const int MAXPATH = 256;//好
√ 要求使用枚舉值/static const來定義類中的常量。 例如, //不好 class Document { public: Document() : VIID(1000){} const int VIID;} //好 class Document { public: enum {VIID = 1000};}//class Document { public: static const int VIID = 1000;}10.4.2. 變數l
推薦不要使用全域變數。l
推薦不要使用static局部變數。
√ 要求所有的成員變數/局部變數都要進行初始化。例如,class Documents{public: Documents() : m_documentCount(0) //初始化{}void NewDocument(const wchar_t* fileName){ bool successful = false;//初始化…}private: int m_documentCount;}l
推薦變數的聲明和初始化能夠一次完成的盡量一次完成。 //不好 int childCount = 0 childCount = pParent->GetChildCount(); //好int childCount = pParent->GetChildCount();
×
不要使返回一個局部變數的引用。 例如, Child* CreateChild() { Child child; Return &child;//不好 }l
推薦變數只在使用之前進行定義,不要把變數定義都放在函數的開頭。 //不好 void BubbleSort(int dataArray[],int count) { int i = 0; int j = 0; int temp = 0; for(i = count-1;i > 1; ++i) { for(j = 0; j < i; ++ j) { } } } //不好 void BubbleSort(int dataArray[],int count) { for(int i = count-1;i > 1; ++i) { for(int j = 0; j < i; ++ j) { } } }
×
不要使用布爾變數直接和0、1進行比較。 //不好 if (flag == 0) if (flag == 1) //好 if (flag) if (!flag)l
推薦判別指標變數是否為空白採用下面的方式。 if (p) if (!p)10.4.3. 類型轉換
×
不要使用強制類型轉換,如果會損失精度或導致不可預測的行為。
×
不要強制轉化const指標變數到non-const。l
推薦使用const_cast和static_cast來實行強制類型轉換,如果強制類型轉換是必需的。10.4.4. 記憶體管理l
推薦盡量少使用指向指標的指標或指標數組。
×
不要使用malloc/free,而要使用new/delete來申請/釋放記憶體。
//不好 int* p = (int*)malloc(sizeof(int)); free(p); p = 0; //好 int* p = new int; delete p; p = 0;
√ 要求delete一塊記憶體的時候,將指向這塊記憶體的指標設定為空白。
//不好 delete p; //好 delete p; p = 0;
√ 要求使用new[]分配的記憶體,要使用delete[]進行釋放。 //不好 int* p = new int[100]; delete p; p = 0; //好 int* p = new int[100]; delete[] p; p = 0;
×
不要跨模組釋放和釋放記憶體。
不好的方式,例如: //模組A中Page* AllocPage(){ … return new Page;}//模組B中Page* pNewPage = AllocPage();delete pNewPage;pNewPage = 0;10.4.5. 控制語句l
推薦少使用/不使用goto語句。
√ 要求優先使用前置的++/--,如果前置和後置的++/--的結果一致。
//不好 for(int i = 0;i < MAXCOUNT; i++) //好 for(int i = 0;i < MAXCOUNT; ++i)
√ 要求將最短的迴圈放在最外層、最長的迴圈放到最內層,如果存在多重迴圈。 //不好 for(int row= 0; row < 100; ++row){ for(int col= 0; col < 5; ++ col) { }}//好 for(int col= 0; col < 5; ++ col){ for(int row= 0; row < 100; ++row) { }}
√ 要求將邏輯判斷移到迴圈體的外面,如果迴圈體內部存在邏輯判斷且迴圈次數很大。 //不好 for(int i = 0; i < LARGECOUNT; ++i){ if (condition) DoSomething(); else DoOtherThing();}//好if (condition){for(int i = 0; i < LARGECOUNT; ++i)DoSomething();}else{for(int i = 0; i < LARGECOUNT; ++i)DoOtherThing ();}
√ 要求每個case語句的結尾都要加上break。
例外:由於邏輯需要,需要重疊多個case分支。
√ 要求default語句的結尾都要加上break。10.4.6. 函數
√ 要求在建構函式中對成員進行初始化,成員初始化的順序同成員的聲明順序。
例如, class PointF { public: //好 PointF () : m_x(0.0F), m_y(0.0F),{…} //不好 PointF () : m_ y(0.0F), m_x(0.0F),{…} private: double m_x; double m_y; }
√ 要求在operator=中檢測右操作符和當前對象指向同一個地址。 例如, Color& operator=(const Color& other){ if ((void*)&other == this) {return *this;} //好 … }
√ 要求在operator=重載中返回*this。
例如,struct Color{public:Color& operator=(const Color& other){ if ((void*)&other == this) {return *this;} //好 … return *this; //好}private: char m_componets[8];}