[CPP] Coding Style

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防止頭文件重包含外,不要定義宏;

 

0NULL

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. 命名空間內容不須要縮進,命名空間不添加額外縮進層次;

相關文章
相關標籤/搜索