C++ Coding Style編程 |
|||
C++不少強大的語言特性致使它的複雜,其複雜性會使得代碼更容易出現bug、難於閱讀和維護。數組 因爲,本人有一點點代碼潔癖,因此依照Google的C++編程規範《Google C++ Style Guide》,用來約束本身平時編程,使得代碼在有效使用C++語言特性的同時易於管理。多線程 |
|||
分類ide |
標題svn |
規則函數 |
備註(示例)性能 |
頭文件單元測試 每.cpp文件都應對應一個.h(.hpp)文件測試 |
#define保護ui |
1. #define PROJECT_PATH_FILE_H_ 防止.h文件被多重包含; |
Project sdk中.h文件sdk/src/abc.h,#define以下: 1 #ifndef SDK_SRC_ABC_H_ 2 #define SDK_SRC_ABC_H_ 3 ... 4 #endif // SDK_SRC_ABC_H_ |
前置聲明 |
1. 使用前置聲明儘可能減小文件中#include的數量; 2. 使用函數時,採用#include方式; 3. 使用類模版時,採用#include方式; 4. 使用普通類時,採用前置聲明; 5. 數據成員爲類自身的指針或引用時,採用前置聲明; |
能夠依賴聲明,就不要依賴定義; |
|
內聯函數 |
1. 不要內聯超過10行的函數; 2. 析構函數應慎重對待; 3. 內聯包含循環或switch語言的函數將得不償失; 4. 虛函數和遞歸函數即便被聲明爲內聯也不必定是內聯函數; |
|
|
-inl.h函數 |
1. 複雜的內聯函數定義,放在後綴名爲-inl.h的頭文件中; |
|
|
函數參數順序 |
1. 函數參數順序:輸入參數在前,輸出參數在後; |
1. 輸入參數爲傳值或常數引用、常指針; 2. 輸出參數爲很是數指針、很是數引用; |
|
包含文件的名字和順序 |
1. 包含.h文件次序:優先的.h文件、C庫、C++庫、其餘庫的.h、項目內的.h; 2. 項目內.h文件應按照項目源代碼目錄樹結構排列,而且避免使用UNIX目錄.(當前目錄)和..(父目錄); 3. 相同目錄下.h文件按字母序排列; |
1. google-awe-project/src/base/logging.h應這樣被包含: #include 「base/logging.h」; 2. 某foo.cc(或foo.cpp)文件中包含.h文件次序: 1 #include 「foo/public/foo.h」 // 優先.cc或.cpp對應的頭文件 2 #include <sys/types.h> // C庫 3 #include <hash_map> // C++庫 4 #include <foo/public/bar.h> // 項目內頭文件 |
|
做用域 |
做用域 |
1. 在.cpp文件(不能在.h文件)中,使用不具名的命名空間; 2. 具名命名空間的名稱基於項目或路徑名稱; 3. 不要使用using指示符,避免污染命名空間,可使用using; 4. 在.cpp文件、.h文件中的函數和類中,可使用using; 5. 在.cpp文件、.h文件中的函數和類中,可使用命名空間別名; 6. 不要使用inline namespace; |
1. 在.cpp文件中的不具名命名空間: 1 namespace 2 { 3 enum {UNUSED, EOF, ERROR}; // 無縮進 4 bool foo() {return EOF;} 5 } // namespace 2. 具名命名空間: 1 namespace mynamespace 2 { 3 class MyClass 4 { 5 public: 6 void foo(); 7 }; 8 } // namespace mynamespace |
嵌套類 |
1. 嵌套類不做爲接口使用時,不要定義爲public; 2. 嵌套類做爲接口的一部分時,置於命名空間中; |
非接口嵌套類: 1 class Foo 2 { 3 private: 4 class Bar 5 { 6 }; 7 }; |
|
非成員函數、靜態成員函數、全局函數 |
1. 使用命名空間中的非成員函數或靜態成員函數,儘可能不使用全局函數; 2. 若肯定須要定義非成員函數,而且只在.cpp文件中使用它,可以使用不具名命名空間或static關聯限定其做用域; |
|
|
局部變量 |
1. 將函數變量儘量置於最小做用域內,在聲明變量時將其初始化; |
|
|
靜態和全局變量 |
1. 禁止class類型的全局(靜態)變量,若必定要使用,可單例模式; 2. 多線程代碼中禁止很是數全局變量,不可以使用函數返回值初始化全局變量; 3. 全局字符串常量,使用C風格字符串,而不要使用STL字符串; 4. 大多數全局變量應該是類的靜態數據成員,或當其只在.cpp文件中使用時,將其定義到不具名命名空間中,或者使用靜態關聯以限制變量的做用域; 5. 靜態成員變量視做全局變量,不能是class類型; |
C風格字符串常量: 1 const char kFrogSays[] = 「ribbet」; |
|
類 |
構造函數職責 |
1. 構造函數只進行那些沒有實際意義的初始化; 2. 若是對象須要有意義的初始化,能夠採用工廠函數或者Init()方法集中初始化; 3. 構造函數禁止調用虛函數; |
|
初始化 |
1. 若類中定義了成員變量,沒有提供其餘構造函數,須要定義一個默認構造函數; |
|
|
顯式構造函數 |
1. 除非必要,單參數構造函數使用C++關鍵字explicit; |
1 explicit Foo(string name); |
|
拷貝構造函數 |
1. 僅在代碼中須要拷貝一個類對象的時候使用拷貝構造函數,不須要拷貝時應使用DISALLOW_COPY_AND_ASSIGN; |
能夠考慮在類的private中添加空的拷貝構造函數和賦值操做,而且只有聲明,不進行定義; 1 #define DISALLOW_COPY_AND_ASSIGN(Type) \ 2 Type(const Type&); \ 3 void operator = (const Type&) 4 5 class Foo 6 { 7 public: 8 Foo(int f); 9 ~Foo(); 10 private: 11 DISALLOW_COPY_AND_ASSIGN(Foo); 12 }; |
|
結構體和類 |
1. 僅當只有數據時使用struct,其它狀況使用class; 2. 對於functor和trait,可使用struct; 3. 類和結構體的成員變量使用不一樣的命名規則(見下面的命名約定); |
|
|
繼承 |
1. 全部繼承必須爲public繼承,採用基類對象做爲成員的方式替代私有繼承; 2. 不要過多使用實現繼承,更多使用組合; 3. 使析構函數爲virtual,若是該類具備虛函數,其析構函數必定爲虛函數; 4. 限定僅在子類訪問的成員函數爲protected,數據成員應始終爲私有; 5. 重定義派生的虛函數時,在派生類中明確聲明其爲virtual; |
|
|
多繼承 |
1. 只有當最多一個基類中含有實現,其餘基類都是以Interface爲後綴的純接口類時才使用多繼承; 2. 純接口必須以Interface爲後綴; |
|
|
接口 |
1. 知足純接口要求時,類以Interface結尾; 2. 接口類必須聲明虛析構函數,析構函數不能純虛函數; |
知足純接口類的要求: * 只有純虛函數和靜態函數(析構函數除外); * 沒有非靜態數據成員; * 沒有定義任何構造函數,如有,須不含參數,且爲protected; * 若是是子類,只能繼承知足以上條件並以Interface爲後綴的類; |
|
操做符重載 |
1. 通常不要重載操做符,若是須要的話,能夠定義相似Equal()、CopyFrom()等函數; 2. STL容器中做爲key要重載operator==或operator<,能夠在聲明容器的時候,建立相等判斷和大小比較的仿函數類型; |
|
|
訪問控制 |
1. 將類數據成員設爲private,並提供相關存取函數; 2. 存取函數的定義通常內聯在頭文件中; |
定義變量m_foo及其取值函數foo()、賦值函數setFoo(); |
|
聲明順序 |
1. 類中定義次序:public:、protected:、private:; 2. 每一塊中,聲明次序爲:typedef和enum、常量(static const數據成員)、構造函數、析構函數、成員函數(含靜態成員函數)、數據成員(除static const數據成員); 3. 宏DISALLOW_COPY_AND_ASSIGN置於private:塊以後,做爲類的最後部分; 4. .cc文件中函數的定義順序和聲明次序一致; |
|
|
編寫短小函數 |
1. 若是函數超過40行,能夠考慮在不影響程序結構的狀況下將其分割; |
|
|
其它C++特性 |
智能指針 |
1. 任何狀況下禁止使用auto_ptr; |
|
引用參數 |
1. 全部按引用傳遞的參數必須爲const引用; 2. 輸入參數採用const引用,輸出參數採用指針; 3. 輸入參數能夠是const指針,但不能夠是non-const引用; |
|
|
函數重載 |
1. 僅在輸入參數類型不一樣、功能相同時使用重載函數; |
|
|
缺省參數 |
1. 禁止使用缺省參數; |
|
|
變長數組和alloca |
1. 禁止使用變長數組和alloca(); |
|
|
友元 |
1. 能夠合理使用友元類及友元函數; |
|
|
異常 |
1. 禁止使用異常; |
|
|
運行時類型識別 |
1. 除單元測試外,禁止使用RTTI; |
|
|
類型轉換 |
1. 使用C++風格而不要使用C風格類型轉換; 2. 除單元測試外不要使用dynamic_cast; |
使用static_case <> ()等C++的類型轉換; |
|
流 |
1. 除日誌接口外,使用printf之類的代替流; |
最好選擇printf + read/write; |
|
前置自增和自減 |
1. 對於迭代器和其餘模板對象使用前綴形式自增和自減運算符; |
|
|
const使用 |
1. 在任何可使用的狀況下使用const; |
|
|
整型 |
1. 使用斷言聲明變量爲非負數,不要使用無符號型; |
|
|
64位下的可移植性 |
1. printf指定的一些類型在32位和64位系統上可移植性不是很好; 2. sizeof(void *) != sizeof(int),能夠用intptr_t定義指針大小的整數; 3. 結構體字節對齊; 4. 建立64位常量時使用LL或ULL做爲後綴; |
int64_t my_value = 0x123456LL; |
|
預處理宏 |
1. 慎用宏,儘量之內聯函數、枚舉和常量代替; 2. 在.h文件中,除了#define防止頭文件重包含外,不要定義宏; |
|
|
0和NULL |
1. 整數用0,實數用0.0,指針用NULL,字符(串)用’\0’; |
|
|
sizeof |
1. 儘量用sizeof(varname)代替sizeof(type); |
|
|
Boost庫 |
1. 只使用Boost中被承認的庫: Compressed Pair:boost/compressed_pair.hpp; Pointer Container:boost/ptr_container,其中不包括ptr_array.hpp和serialization; |
|
|
命名約定 最重要是一致性 |
通用命名規則 |
1. 函數、變量、文件命名應具備描述性,不要過分縮寫,類型和變量應是名詞,函數名能夠用「命令性」動詞; 2. 除非放到項目外也很是明瞭,不然不要使用縮寫; |
1. int num_completed_connections; 2. int num_dns_connections; 3. int error_count; // Good. int error_cnt; // Bad. |
文件命名 |
1. 文件名要所有小寫,能夠包含’_’或’-’,按項目約定來; 2. 源文件以.cc結尾,頭文件以.h結尾;
|
可接受的文件命名: my_useful_class.cc my-useful-class.cc myusefulclass.cc |
|
類型命名 |
1. 類型命名每一個單詞以大寫字母開頭,不包含下劃線; |
1. 類型:類、結構體、類型定義(typedef)、枚舉; 2. 如:MyExcitingClass、UrlTable; |
|
變量命名 |
1. 變量名一概小寫,單詞間如下劃線相連,類的成員變量如下劃線結尾; 2. 結構體數據成員能夠和普通變量同樣,不用像類的成員數據那樣如下劃線結尾; 3. 全局變量以g_做爲前綴; |
1. 1 my_exciting_local_variable 2 my_exciting_member_variable_ 2. 1 struct UrlTablePoperties 2 { 3 sting name; 4 int num_entries; 5 }; |
|
常量命名 |
1. 在名稱前加k; |
const int kDayInAWeek = 7; |
|
函數命名 |
1. 普通函數爲大小寫混合,存取函數則須要與變量名匹配; 2. 其它短小的內聯函數可使用小寫字母; |
1 MyExcitingMethod() 2 set_my_exciting_member_variable() |
|
命名空間 |
1. 命名空間所有爲小寫; |
|
|
枚舉命名 |
1. 枚舉值所有大寫,單詞間如下劃線相連; |
|
|
宏命名 |
1. 若是要使用,其命名方式與枚舉命名一致; |
|
|
代碼註釋 |
註釋風格 |
1. 使用//或/* */,統一就好; |
|
文件註釋 |
1. 在每個文件開頭加入版權公告,而後是文件內容描述; |
|
|
類註釋 |
1. 類的定義要附着描述類的功能和用法的註釋; 2. 若是類的實例可被多線程訪問,使用時務必文檔說明; |
|
|
函數註釋 |
1. 函數聲明處註釋描述函數功能,定義處描述函數實現; 2. 構造/析構函數前無需註釋; |
1. 函數聲明處註釋的內容: * inputs及outputs; * 類成員函數:函數調用期間對象是否須要保持引用參數,是否會釋放這些參數; * 若是函數分配了空間,須要由調用者釋放; * 參數是否能夠爲NULL; * 是否存在函數使用的性能隱憂; * 若是函數是可重入的,其同步前提是什麼; 2. 函數定義處定義的內容: 註釋說明函數功能和實現要點; |
|
變量註釋 |
1. 一般變量名自己足以很好說明變量用途,特定狀況下,須要額外註釋說明; |
|
|
實現註釋 |
1. 對於實現代碼中巧妙的、晦澀的、有趣的、重要的地方加以註釋; 2. 相鄰幾行都有註釋的,能夠調整使//縱向對齊; |
|
|
TODO註釋 |
1. 對那些臨時的、短時間的解決方案,或已經夠好但並不完美的代碼使用TODO註釋; |
// TODO(hanyp@126.com): change this. |
|
格式 |
行長度 |
1. 每一行代碼字符數不超過80; |
|
空格 |
1. 只使用空格,每次縮進2個字符。設定編譯器將Tab轉爲空格; |
|
|
函數聲明和定義 |
1. 函數名、返回類型、參數儘量在同一行; 2. 若是函數爲const的,const應與最後一個參數位於同一行; 3. 獨立行的參數保持4個空格的縮進; |
1 ReturnType ClassName::FunctionName(Type ar_name1, Type par_name2) 2 { 3 DoSomething(); 4 } |
|
函數調用 |
1. 同函數聲明和定義格式; |
|
|
條件語句 |
1. 不要再圓括號內加空格; |
1 if (condition) 2 { 3 ... 4 } 5 else 6 { 7 ... 8 } |
|
循環和選擇語句 |
1. 類比條件語句; |
|
|
指針和引用表達式 |
1. 句點(.)或箭頭(->)先後不要有空格,指針/地址操做符(*、&)後不要空格; 1. 在聲明指針、引用變量或參數時,(*、&)與類型名緊挨; |
|
|
布爾表達式 |
1. 若是一個布爾表達式超過標準行寬,斷行要統一; |
|
|
函數返回值 |
1. return表達式中不要使用圓括號; |
|
|
變量及數組初始化 |
1. 使用()格式; |
int x(3); |
|
預處理指令 |
1. 預處理指令不須要縮進; |
|
|
類格式 |
1. public、protected、private不須要縮進,函數及變量定義縮進2空格; |
|
|
初始化列表 |
1. 構造函數初始化列表放在同一行或按四格縮進並排幾行; 2. ‘:’先後各空一格; |
|
|
命名空間格式 |
1. 命名空間內容不須要縮進,命名空間不添加額外縮進層次; |