嚴謹編碼風格的重要性:
1.便於代碼合並,滿足團隊開發的需要
2.合格程序員的必備素質
3.防止編碼錯誤
4.易讀易理解
Google C++編碼規范(中文版)
https://zh-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/
1.頭文件盡可能多的使用前向聲明
好處:較少的文件依賴,減少編譯時間. 更加明確的類的依賴關系.
1 //.h中類B使用類A,使用前向聲明就不需要包含類A的頭文件,減少編譯工作量 2 class CA; //前向聲明一個類A 3 class CB 4 { 5 public: 6 CA* m_pA;//聲明類A的指針 7 CA* GetClassA(CA *pA, CA &a); //聲明使用類A作為形參或返回值類型的函數 8 //CA m_A; Error,不能定義類A的對象 9 };
2.函數的參數順序,輸入參數在前,輸出參數在后
輸入參數一般為傳值或者指針,引用,前面加const
輸出參數一般為非常量指針或者引用
好處:根據參數的位置明確參數的作用,一目了然
1 //輸入參數: nInput cInput szInput 2 //輸出參數: nOutPut 3 void Fun(const int nInput, const char cInput, const char* pStrInput, int &nOutPut);
3.頭文件的包含順序
stdafx.h預編譯頭文件
先包含當前源文件對應的頭文件
C系統頭文件
C++系統頭文件
其它庫頭文件
本項目其它頭文件
每個區域之間空一行
好處:增加可讀性
1 #include "stdafx.h" //預編譯頭文件 2 3 #include "test.h" //當前源代碼對應的頭文件 4 5 #include <stdio.h> //C標准庫 6 7 #include <iostream> //C++標准庫 8 9 #include "library/read.h" //其它庫頭文件 10 #include "library/write.h" 11 12 #include "one.h" //當前項目下其它頭文件 13 #include "two.h"
4.局部變量初始化,聲明變量后立即進行賦值初始化
好處:避免未初始化產生的潛在錯誤
1 int nA = 0; 2 char szB = '\0'; 3 float fC = 0.00f; 4 char szBuff[16] = {0}; //注意:初始化時指定的的元素個數比數組大小少,剩下的元素都回被初始化為0 5 StPeople tPeople = {0};
5.類的初始化
1 class CStudent 2 { 3 public: 4 CStudent():m_nAge(0),m_fScore(0.00f){} 5 CStudent(int nAge, float fScore):m_nAge(nAge),m_fScore(fScore){}; 6 private: 7 int m_nAge; 8 float m_fScore; 9 }; 10 int _tmain(int argc, _TCHAR* argv[]) 11 { 12 CStudent student; //使用無參的構造函數初始化 m_nAge=0 m_fScore=0.00f 13 CStudent studentTwo(20,99.5); //使用初始化例表構造函數初始化 m_nAge=20 m_fScore=99.5f 14 }
6.局部變量是個對象,應該避免多次調用構造與析構
1 //這里循環一千次,每次循環都得實例化對象,調用構造與析構
2 for(int i = 0; i<1000; i++)
3 { 4 CTest test; 5 test.Out(); 6 } 7 //下面同樣循環一千次,在外部實例化對象,只調用一次構造與析構 8 CTest testTwo; 9 for(int j = 0; j<1000; j++) 10 { 11 testTwo.Out(); 12 }
7.結構體和類使用, 只有當成員全部為數據時使用結構體,其它時一律使用類.
C++中結構體和類起到同樣作用,唯一區別是結構體默認成員和方法是public,而類默認是private
8.操作符重載,盡量不要用操作符重載,定義一個函數來處理顯得更加直觀
1 class CPerson 2 { 3 public: 4 CPerson(int nAge):m_nAge(nAge){} 5 //重載==運算符 6 bool operator==(const CPerson &ps) 7 { 8 if (this->m_nAge == ps.m_nAge) 9 { 10 return true; 11 } 12 return false; 13 } 14 //使用Equal函數 15 bool Equal(const CPerson &ps) 16 { 17 return this->m_nAge == ps.m_nAge; 18 } 19 private: 20 int m_nAge; 21 }; 22 int _tmain(int argc, _TCHAR* argv[]) 23 { 24 CPerson person1(20); 25 CPerson person2(20); 26 if(person1 == person2) 27 { 28 printf("person1 == person2\r\n"); 29 } 30 31 if(person1.Equal(person2)) 32 { 33 printf("person1 == person2\r\n"); 34 } 35 36 getchar(); 37 }
9.將類的數據成員私有化,提供Get Set方法進行訪問, 不使用對象,xxxx方式訪問
好處:提高代碼封裝性,有利於調試.
當數據成員出錯時,只需在Get Set方法下斷調試即可. 反之使用對象.xxx方式訪問,出錯時需要在所有調用處下斷,不利於調試.
1 class CPerson 2 { 3 public: 4 CPerson(int nAge):m_nAge(nAge){} 5 int GetAge() 6 { 7 return this->m_nAge; 8 } 9 void SetAge(const int nAge) 10 { 11 this->m_nAge = nAge; 12 } 13 private: 14 int m_nAge; 15 }; 16 int _tmain(int argc, _TCHAR* argv[]) 17 { 18 CPerson person1(20); 19 printf("age = %d\r\n",person1.GetAge()); 20 person1.SetAge(30); 21 getchar(); 22 }
10.類中的聲明順序, 先聲明public塊,再聲明protected塊,再聲明private塊,這三塊中聲明的順序一致
1 class CPerson 2 { 3 public: 4 //typedef 5 typedef vector<int> VectorInt; 6 //常量 7 const int m_kNum; 8 //構造和析構函數 9 CPerson(int nAge):m_kNum(100),m_nAge(nAge){} 10 ~CPerson(){} 11 //成員函數 12 int GetAge() 13 { 14 return this->m_nAge; 15 } 16 void SetAge(const int nAge) 17 { 18 this->m_nAge = nAge; 19 } 20 //數據成員 21 protected: 22 //聲明順序同上 23 private: 24 //聲明順序同上 25 int m_nAge; 26 };
11.編寫短小的函數,盡量不要超過40行
好處:方便提取重復代碼進行封裝,便於他人閱讀和修改,方便調試
12.不使用函數重載,直接使用函數名進行區分
好處:過多的函數重載種類會使調用者無從選擇
1 //函數重載 2 CPerson* GetPerson(const int nAge); 3 CPerson* GetPerson(const Sex emSex); 4 CPerson* GetPerson(const char* pStrName); 5 6 //直接利用函數名進行區分 7 CPerson* GetPersonFromAge(const int nAge); 8 CPerson* GetPersonFromSex(const Sex emSex); 9 CPerson* GetPersonFromName(const char* pStrName);
13.函數參數禁止使用缺省參數
好處:避免他人調用函數時錯誤的理解
14.迭代器上使用前置自增自減(++i --i)
好處:提高迭代器訪問的執行效率, 相比后置自增自減而言
15.當函數參數為對象時,盡量使用指針或者引用方式傳遞
//直接傳遞,需要構造一個新的對象,這個新的對象又得構造和析構,影響性能 void GetPeoson(const CPerson person); //使用指針或引用方式傳遞實參,不需要構造新的對象 void GetPesSon(const CPerson *pPerson); void GetPeoson(const CPerson &person);
16.使用sizeof(變量名),而不是使用sizeof(數據類型)
好處:當修改變量的數據類型后,sizeof不需要同步更新成新的數據類型
17.格式要求
函數中返回值與函數名在同一行,如果參數過多需要進行換行並且對齊,每一行一個參數
1 void SetWindow(HWND hWnd, 2 int nWidth, 3 int nHeight, 4 int nX, 5 int nY, 6 DWORD dwStyle);
if和else if語句塊的括號需要另起一行,方便閱讀
1 if(aa > bb) 2 { 3 //...... 4 } 5 else if(aa > cc) 6 { 7 //..... 8 }
適當添加空格,使代碼美觀更利於閱讀
1 int nA, nB, nC; 2 nC = nA + nB;