C++编码规范

一、    文件名命名规范

  1. 文件的名字需和承载的类之间有一定的关联性,而且常用的公共头文件需要定义得比较简短
  • 文件名采用全部小写的方式,不允许大小写混合的方式

二、    源程序文件

  1. 源文件段落依下列顺序:
  2. 序言
  3. 系统头文件引用(include)
  4. 用户头文件引用(include)
  5. 全局常量宏定义(define)
  6. 全局函数宏定义(define)
  7. 全局类型定义(typedef)
  8. 全局枚举类型定义(enums)
  9. 全局变量说明(extern)
  10. 全局变量说明(non-static)
  11. 全局变量说明(static)
  12. 函数(通常从最高层开始,按层次横向排列。如果定义较多的独立的公用函数,可以考虑按字母顺序排列。
  13. 序言内容应包括版权声明、内容描述、格式如下:

/*********************************************************************

 *  Copyright 2016  by 99letou.

 *  All right reserved.

 *

 *  功能:*****文件

 *

 *  Edit History:

 *

 *    2016/04/04 – Created by David.

 *    2006/04/06 – Modified by John to print output in the new form.

 */

  • 段落之间用空行分隔。
  • 文件长度尽可能在1000行之内。
  • 每行长度尽可能不要超过79列。

三、    头文件

  1. 头文件开头注释:

/**
 * Description: This is a test program
 */ 

  • 每个头文件采用下面的形式避免被重复引用:

#ifndef EXAMPLE_H

#define EXAMPLE_H

… /* body of example.h file */

#endif /* EXAMPLE_H */

  • 多个源文件引用的说明放入头文件中。
  • 说明函数或外部变量的头文件应在定义该函数或变量的文件中引用。
  • 引用头文件不要使用绝对路径。使用<filename.h>引用系统头文件;使用“filename.h””引用用户头文件。

四、    数据变量说明

  1. 常量的命名规范:

    常量名由全大写字母组成,单词间通过下划线来界定

  • 成员变量的命名规范:

    m+_+[变量类型]+变量名

    m后带上明确表达变量意义的英文名词而不要用难以表达意义的缩写。且m后的变量名首字母必须大写。如:

    class CMyGame

    {

        private :

           CPoint m_Point;<―――普通类型

           CGame* m_pGame;<―――指针类型

           Int m_nGameID;<―――整数类型

    }

  • 函数参数的命名规范:

采用波浪法来定义函数参数变量。同样的,也必须使用可以明确表达变量意义的英文名词,而不仅仅是缩写。

[变量类型]+变量名

如定义一个读取文件的函数,并且用参数传入一个文件名

public boolean readFile(String strFileName)

{

       m_sFileName = strFileName;

}

  • 局部变量的命名规范:

采用全部小写的方式定义局部变量名。而且尽量用有意义的名词作为变量名。

局部变量不需要在前面增加变量类型标识。

public boolean readFile()

{

              String filename = “e.ext”;

}

  • 局部循环变量的命名规范:

用小写的i、j、k依次作为循环变量

       如:

       for (int i = 0 ; i < 10 ; i ++ )

{

       for (int j = 0 ; j <10 ; j ++ )

       {

}

}

  • 临时变量的命名规范:

一般情况下尽量使用有意义的变量名,如果是某变量的临时变量,可采用前面增加tmp前缀的方式。如果实在没办法,可采用tmp、temp等作为临时变量名,但不可以过多定义诸如tmp1、tmp2等变量,如果出现此情况,则必定可以采用有意义的名词代替。

       int tmpserialno = mSerialNo++;

       tmpserialno %= 10;

       mSerialNo = tmpserialno;

  • 枚举常量

采用波浪法加E前缀来定义枚举常量。同样的,也必须使用可以明确表达变量意义的英文名词,而不仅仅是缩写。且E后首字母必须大写

正确写法:

enum ECHARTYPE
{
    CHARTYPE_SPACE = _ISspace,
    CHARTYPE_PRINT = _ISprint,
    CHARTYPE_CNTRL = _IScntrl,
};

错误写法:

enum ECHARTYPE{ SPACE = _ISspace, PRINT = _ISprint, CNTRL = _IScntrl };

  • 变量定义范围建议:

尽量在变量的有效范围内定义之,如果一个变量仅仅在某个函数内使用到,则把其定义为一个成员变量就是不适合的。在如某些变量只在循环内用到,则应该在循环体内定义之,而不要随意括大其定义范围。

  • 变量类型:

基本类型(保留类型)

char c cMyChar;
bool b bMyBool;
int/short/long n nMyInt;
float/double f fMyFloat;
Long64 l lMyLong;
String/char*(当明确知道是用作字符串的情况下) str strMyString
map map mapPlayers
vector vec vecPlayers
list lst lstPlayers
multimap mmap mmapState

特殊类型

Handle h hFile;
  1. 指针类型:

在变量类前增加p标识,作为标识此变量为指针类型,如:

       int *pKey = NULL;

       CDateTime* pDateTime = new CDateTime(0);

  1. 数组变量命名规范:

对于数组类型的变量,需要采用复数s以标识此为数组变量。如:

int m_nKeys[100];

double dValues[200];

CMyClass Strings[200];

特例:对于char buf[200]这种定义,由于其使用习惯原因,不需要采用数组前缀。

       对于数组指针变量,同样在类型前增加p标识。在删除的时候,必须用delete[]的方式删除动态数组,以保证数组内的实例被调用析构函数。

       CDateTime* pBirthdays = new CDateTime[20];

    ….

       delete[] pBirthdays;

       int* m_pnKeys = new int[20];

五、    类说明

  1. 类名命名规范

       根据各种类的类型和用途,采用不同前缀+名词的命名方式。名词采用波浪法,必须使用可以明确表达变量意义的英文名词。

  • 前缀
  • 普通类(C)

       一般类,采用C+名词的方式命名

例如:

Class CPerson

{

Protected :

String m_strName;

String m_strNickName;
};

  • 接口类(I)

    对于无任何实现的纯虚类,称为接口类,这些类的特点都是无任何成员变量,存在需要其他实现类实现的纯虚函数。

       接口类必须采用I+名词的方式命名。

例如:

class IDataInput

{

       Public :

              virtual ~IDataInput() {};

              virtual void read() = 0;

}

  • 结构体(T)

       Struct,结构体,必须以T+名词的方式命名。

例如:

       typedef struct _t_mystruct

       {

              Unsigned int number;

              Unsigned int value;

              Char name[255];

       }TMyStruct,* TMyStructPtr;

  • 模板类

       模板类,必须以全小写命名。

例如:

template<class T,allocator A>

class screen : public map<T,A>

{
}

  • 类成员的初始化(Member initialization lists

成员的初始化必须在构造函数名的下一行开始

正确写法:

gribble::gribble()
:m_private_data(0), m_more_stuff(0), m_helper(0)
{
}

错误写法:

gribble::gribble():m_private_data(0),m_more_stuff(0), m_helper(0)
{
}

  • 类成员变量必须采用private的定义,不允许使用public定义,并置于类定义的最后,另外用gettersetter的函数访问和修改之(在需要考虑程序大小的时候可以忽略此规则)

    class CTest

    {

           public : 

    int getTopicID()      //获取话题ID

    { 

    return m_nTopicID;
    }

    void setTopicID(int nTopicID) //设置话题id

           {

                  m_nTopicID = nTopicID;

           }

           private:

      TInt m_nTopicID;

      }

  • 一个方法只完成一个任务,不要把多个任务放在一个方法中,即使那些任务非常小
  • 功能类的方法的大小尽可能不要超过100

六、    函数说明

  1. 每个函数前加入注释块,描述函数功能、输入参数和返回值,必要时应说明其功能、用法、重要设计决策与副作用。

/**

    * @description : PrintOneMsg

    * @input param : nUserID     — 用户ID

    * @output param:  nMoney– 玩家体力

    * @return: 0  — success

               other — false

   * @exception CException reason

 */

int PrintOneMsg((int nUserID,int & nMoney)

{

function body;

return 0;

}

  • 函数名称原则上采用动词名词的组合形式,函数名称采用波浪法,第一个单词首字母采用小写,后面的单词的首字母采用大写

如:int getTopicID()

  • 函数的参数个数尽可能不要超过5个。
  • 函数体的开、闭花括号写在第一列,分别占一行。函数体的局部变量说明和代码缩进4格。
  • 业务逻辑函数的大小尽可能不要超过200

七、    代码注释规范

为了能更好的体现代码即详细设计文档这个意图,在对代码注释的时候,需遵守下列的规范。

  1. 用“注释块”描述数据结构、算法等,放在被注释的程序段前:

/*

 *  Here is a block comment.

 *  The opening slash-star and closing star-slash are alone on a line.

 *  …

     */

  • “单行注释”放在被注释的程序段前,并与该程序段对齐:

if (argc > 1)

{

    // Get input file frmm command line

if (freopen(argv[1], “r”, stdin) == NULL)

{

        perror(argv[1]);

    }

}

  • 放在代码行尾的“短注释”与被注释的代码分开至少一个空格:

if (a == EXCEPTION)

{

b = TRUE;           // special case

    BODY

}

else

{

b = isprime(a);     //works only for odd a

BODY

}

  • 函数抛出异常注释规范

对于可能抛出异常的类方法、函数,在注释中说明所抛出异常的类名和产生异常的原因;

注释中采用如下语法

/**

* @exception fully-qualified-class-name description

*/

fully-qualified-class-name:方法声明的异常名

description:产生异常的原因

例如:

  /**

   * 连接数据库

   * @ exception CSQLException 数据库连接失败,具体原因请根据sqlcode查阅数据库错误代码说明

   */

virtual bool connect()=0;

八、    构造与析构

  1. 类构造函数,做非资源变量的初始化动作,原则上不进行任何可能出现错误的操作,如分配内存,调用资源等。
  2. delete new ,freemalloc,delete[] new[]必须成对使用,否则不保证会不会出现问题。

九、    异常处理

  1. 所有的异常抛出都必须以对象形式,而不是能以new 的指针形式。而捕获的时候就可以统一用引用的方式进行捕获。这样在性能和开销方面不会加大的同时,也无需关心指针的删除问题。

       try

       {

              throw CDateTimeException(“datetime format error”);

       }

       catch (CDateTimeException& e)

       {

              cout<<e.what()<<end;

       }

十、    其他良好的编程习惯

  1. 缩进采用tab而不是用spacetab的缩进显示距离建议为4个空格
  2. 用一个空行来分开代码和逻辑的分组;
  3. 花括号“{”、“}”需独立一行,而不像if for等可以和括号同一行,而且必须与if等缩进相同的空间

如:if ( test == 1 )

              {

       }

  • 在每个运算符和括号的前后都空一格。
  • warning编译
  • switch语句中出现的fall-through应加以注释:

switch (expr)

{

case ABC:  //注释

{

statement

break;

}

case DEF: //注释

{

statement

break;

}

     default: XYZ:

     {

       statement;

break;

}

}

关注公众号“康波之道”回复“小程序”获取1000个小程序打包源码。回复“大数据”获取多本大数据电子书

发表评论

邮箱地址不会被公开。 必填项已用*标注