C++编码规范
严谨编码风格的重要性:
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;