1、頭文件c++
1. #define的保護:全部頭文件都應該使用#define防止頭文件被多重包含(multiple inclusion),命名格式:程序員
<PROJECT>_<PATH>_<FILE>_H_windows
爲保證惟一性,頭文件的命名應基於其所在項目源代碼樹的全路徑。 數組
2.頭文件依賴:使用前置聲明(forward declarations)儘可能減小.h文件中#include的數量。避免多米諾骨牌效應安全
e.g.頭文件中用到類File,但不須要訪問File的聲明,則頭文件只需前置聲明class File;無需#include "file/bash/file.h"。bash
在頭文件中如何作到使用類Foo而無需訪問類的定義?多線程
1)將數據成員類型聲明爲Foo* 或Foo &;函數
2)參數、返回值類型爲Foo的函數只是聲明(但不定義實現);單元測試
3)靜態數據成員的類型能夠被聲明爲Foo,由於靜態數據成員的定義在類定義以外。測試
有時,使用指針成員替代對象成員的確更有意義,然而,這樣的作法會下降代碼可讀性及執行效率。若是僅僅爲了少包含頭文件,仍是不要這樣代替的好。
3.內聯函數:只有當函數只有10行甚至更少時纔將其定義爲內聯函數。對於析構函數應慎重對待,析構函數每每比其表面看起來要長,由於有一些隱式成員和基類析構函數(若是有的話)被調用!另外內聯那些包含循環或switch語句的函數是得不償失的,除非在大多數狀況下,這些循環語言從不執行。複雜的內聯函數的定義,應放在後綴爲-inl.h的頭文件中。
4.函數參數的順序:輸入參數在前,輸出參數在後(輸入和輸出)。輸入參數使用值傳遞或者常數引用傳遞,輸出參數使用很是數指針傳遞。
5.包含文件的名稱和次序:C庫、C++庫、其餘庫的.h、項目內的.h。避免隱藏依賴。
2、做用域
1.命名空間:在.cc文件中,提倡使用不具名的命名空間,使用具名命名空間時,其名稱可基於項目或路徑名稱,不需使用using指示符。
2.嵌套類:當公開嵌套類做爲接口的一部分時,雖然能夠直接將他們保持在全局做用域中,但將嵌套類的聲明置於命名空間時更好的選擇。只能在被嵌套類的定義中才能前置聲明嵌套類。不要將嵌套類定義爲public,除非它們是接口的一部分。
3.非成員函數、靜態成員函數和全局函數:使用命名空間中的非成員函數或靜態成員函數,儘可能不要使用全局函數。
1)非成員函數不該依賴於外部變量,並儘可能置於某個命名空間中。相比單純爲了封裝若干不共享任何靜態數據的靜態成員函數而建立類,不如使用命名空間。
2)定義於同一編譯單元的函數,被其餘編譯單元直接調用可能會引入沒必要要的耦合和鏈接依賴;靜態成員函數對此尤爲敏感,能夠考慮提取到新類中,或者將函數置於獨立庫的命名空間中。
3)若是確實須要定義非成員函數,又只是在.cc文件中使用它,可以使用不具有命名空間或static關聯限制其做用域。
4.局部變量:將函數變量儘量置於最小做用域內,在聲明變量時將其初始化。
5.全局變量:class類型的全局變量時被禁止的,內建類型的全局變量是容許的,固然多線程代碼中很是數全局變量也是被禁止的,永遠不要使用函數返回值初始化全局變量。
1)若是必定要使用class類型的全局變量,請使用單件模式
2)對於全局的字符串常量,使用C風格的字符串,而不要使用STL的字符串;
3)靜態成員變量視做全局變量,因此,也不能是class類型!
總結:做用域的使用,除了考慮名稱污染、可讀性以外,主要是爲下降耦合度,提升編譯、執行效率。
3、類
1.不在構造函數中作太多邏輯相關的初始化,可能的話使用Init()方法集中初始化有意義的數據。
在構造函數中執行操做引發的問題有:
1)構造函數中不易報告錯誤,不能使用異常。
2)操做失敗會形成對象初始化失敗,引發不肯定狀態。
3)構造函數內調用虛函數,調用不會派發到子類實現中,即便當前沒有子類化實現,未來還是隱患。
4)若是有人建立該類型的全局變量(雖然違背了上節提到的規則),構造函數將在main()以前被調用,有可能破壞構造函數中暗含的假設條件。
2.編譯器提供的默認構造函數不會對變量進行初始化,若是定義了其餘構造函數,編譯器再也不提供,須要編碼者自行提供默認構造函數;
3.爲避免隱式轉換,需將單參數構造函數聲明爲explicit(明確的);例外,在少數狀況下,拷貝構造函數能夠不聲明爲explicit;特地做爲其餘類的透明包裝器的類。
4.爲避免拷貝構造函數,賦值操做的濫用和編譯器自動生成,可目前聲明其爲private且無需實現;僅在代碼中須要拷貝一個類對象的時候使用拷貝構造函數,不須要拷貝時應使用DISALLOW_COPY_AND_ASSIGN。
5.僅在做爲數據集合時使用struct;
6.組合>實現繼承>接口繼承>私有繼承,子類重載的虛函數也要聲明virtual關鍵字,雖然編譯器容許不這樣作;
7.避免使用多重繼承,使用時,除一個基類含有實現外,其餘積累均爲純接口;
8.接口類類名爲Interface爲後綴,除提供帶實現的虛析構函數、靜態成員函數外,其餘均爲純虛函數,不定義非靜態數據成員,不提供構造函數,提供的話,聲明爲protected;
9.爲下降複雜性,儘可能不重複操做符,模板、標準類中使用時提供文檔說明;
10.存取函數通常內聯在頭文件中;
11.聲明次序:public->protected->private;
12.函數體儘可能短小、緊湊、功能單一。
4、C++特性
1.對於智能指針,安全第1、方便第二,儘量局部化;
2.引用形參加上const,不然使用指針形參;
3.函數重載的使用要清晰、易讀;
4.鑑於容易誤用,禁止使用缺省函數參數(值得商榷);
5.禁止使用變長數組;
6.合理使用友元;
7.爲了方便代碼管理,禁止使用異常(值得商榷);
8.禁止使用RTTI,不然從新設計代碼;
9.使用c++風格的類型轉換,除單元測試外不要使用dynami_cast;
10.使用流還printf+read/write,it is a problem;
11.能用前置自增/減,不用後置自增/減;
12.const能用則用,提倡const在前;
13.使用肯定大小的類型,除位組外不要使用無符號型;
14.格式化輸出及結構對齊時,注意32位和64位的系統差別;
15.除字符串化、鏈接外儘可能避免使用宏;
16.整數用0,實數用0.0,指針用NULL,字符(串)用'\0';
17.用sizeof(varname)代替sizeof(type);
18.只使用Boost中被承認的庫。
5、命名規則
1.整體規則:不要隨意縮寫。除函數名可適當爲動詞外,其餘命名儘可能使用清晰易懂的名詞;
2.宏、枚舉等使用所有大寫+下劃線;
3.變量(含類、結構體成員變量)、文件、命名空間、存取函數等使用所有小寫+下劃線,類成員變量如下劃線結尾,全局變量以g_開頭;
4.普通函數、類型(含類與結構體、枚舉類型)、常量等使用大小寫混合,不含下劃線;
5.參考現有或相近命名約定。
6、註釋
1.關於註釋風格,不少c++程序員更喜歡行註釋,c程序員或者對塊註釋依然情有獨鍾,或者在文件頭大段大段的註釋時使用塊註釋;
2.TODO;
3.適當的縮進;
7、格式
1.行寬原則上不超過80列;
2.儘可能不使用非ASCII字符,若是使用的話,參考UTF-8格式(尤爲是UNIX/LINUX下,Windows下能夠考慮寬字符),儘可能不將字符串常量耦合到代碼中,好比獨立出資源文件,這不只僅是風格問題了;
3.UNIX/LINUX下無條件使用空格,MSVC的話使用Tab也無可厚非;
4.函數參數、邏輯條件、初始化列表;要麼全部參數和函數名放在同一行,要麼全部參數並排分行;
5.除函數定義的左大括號能夠置於行首外,包括函數/類/結構體/枚舉聲明、各類語句的左大括號置於行尾,全部右大括號獨立成行;
6../->操做符先後不留空格,*/&不要先後都留,一個就可,靠左靠右依各人喜愛;
7.預處理指令/命名空間不適用額外縮進,類/結構體/枚舉/函數/語句使用縮進;
8.初始化用=仍是()依我的喜愛,統一就好;
9.return不要加();
10.水平/垂直留白不要濫用,怎麼易讀怎麼來。
8、規則之例外
1.windows代碼
1)不要使用匈牙利命名法,使用Google命名規則,包括對源文件使用.cc擴展名;
2)Windows定義了不少原有內建類型的同義詞,如DWORD、HANDLE等等,在調用Windows API時這是徹底能夠接受甚至鼓勵的,但仍是儘可能使用原來的C++類型,例如,使用const TCHAR *而不是LPCTSTR;
3)使用Microsoft Visual C++進行編譯時,將警告級別設置爲3或更高,並將全部warnings當作errors處理;
4)不要使用#pragma once;做爲包含保護,使用C++標準包含保護,包含保護的文件路徑包含到項目樹頂層;
5)除非萬不得已,不然不使用任何不標準的擴展,如#pragma和_declspec,容許使用_ _declspec(dllimport)和_ _declspec(dllexport),但必須經過DLLIMPORT和DLLEXPORT等宏,以便其餘人在共享使用這些代碼時容易放棄這些擴展。
在windows上,只有不多一些偶爾能夠不遵照的規則:
1)一般咱們禁止使用多重繼承,但在使用COM和ATL/WTL類時可使用多重繼承,爲了執行COM或ATL/WTL類及其接口時可使用多重實現繼承;
2)雖然代碼中不該使用異常,但在ATL和部分STLl(包括Visula C++的STL)中異常被普遍使用,使用ATL時,應定義_ATL_NO_EXCEPTIONS以屏蔽異常,你要研究一下是否也屏蔽掉STL的異常,若是不屏蔽,開啓編譯器異常也能夠,注意這只是爲了編譯STL,本身仍然不要寫含異常處理的代碼;
3)一般每一個項目的每一個源文件中都包含一個名爲StdAfx.h或precompile.h的頭文件方便頭文件預編譯,爲了使代碼方便與其餘項目共享,避免顯式包含此文件(precompile.cc除外),使用編譯器選項/F1以自動包含;
4)一般名爲resource.h,且只包含宏的資源頭文件,沒必要拘泥於此風格指南。