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;
posted @ 2019-11-20 20:55  SmallOverFllow  阅读(1750)  评论(0编辑  收藏  举报