一基本原则:
用c++风格来写c++代码,而不是c风格
代码尽量模块化,低耦合
对复杂度较高的逻辑做拆分,尽量避免高度复杂的函数
在标准c++的支持特性范围内,禁止使用编译器的方言扩展。仅在确实需要用到标准c++不支持的特性的情况下酌情慎用方言。
二、代码风格细则
说明:
下文中,把包括基本数据类型在内的一切类型的内存实例,统称对象
1,缩进和对齐
必须:1)namespace 不产生缩进,namespace的起始括号不可另起新行
2)使用空格缩进,行首缩进距离以为4空格为单位
3)private等访问控制关键字相对于类名所在行不缩进
4)括号内发生断行时新行从前一半括号的列后开始
5)函数和类等声明时,标记主体开始和结束的花括号,必须各单独占一行
6)单目运算符和算子之间连续,不留空,不能换行
7)双目运算符和两个算子之间各留一个空格,必要时可以换行
8)三目运算符(?:)的算符和算子之间必须各留一个空格,必要时可以换行
9)每个对象的声明或定义,单独占一行,即不许在一行内同时声明或定义多个对象。
10)成员引用符号(. 和 -> )和作用域标示符(::)两端不许留空,不许换行
2,整数类型
必须:禁止使用 char,short,int,long 等长度不明确的类型来表示整数,用int8_t, int16_t等确定长度类型代替
例外:以上限制仅限表达整数语义,char, wchar_t等依然用于表示字符类型
3,struct关键字
必须:1)自定义struct类型不许包含虚函数和除了operator overload和constructor之外的成员函数(包括不许包含destructor);
2)struct类型的定义不许出现在继承体系中
3)定义或声明某种struct类型的对象时,不带struct关键字。例子 :
struct ST{};
ST st1; //推荐的用法
struct ST st2;//禁止的用法
4)尽量保证struct都是trival_copy_able的
例外:对于 3),在和c语言的api时,可以在局部遵循c风格带struct关键字
4,函数规模
必须:单个函数最多不超过200行
推荐:单个函数最多不超过80行
例外:无
2,函数条件分支数量
必须:单个函数内部的分支跳转的数量,最多不能超过20个
推荐:不超过10个
例外:switch 结构可以不受此限制;函数首部的可执行条件检查部分不参与计数
3,多重循环
必须:禁止超过4层的循环
推荐:不超过3层
建议:少用超过2层的循环
例外:无
4,条件分支
必须:禁止超过4层的if嵌套
推荐:不要超过3层
例外:无
5,数组
必须:禁止使用原生数组,用stl容器代替
例外:和c语言接口的地方;临时用作buff的情况
6,字符串
必须:禁止使用char数组作为字符串,一律用std::string
例外:和c语言接口的地方
7,宏函数和宏常量
必须:1)禁止自定义宏函数
2)禁止自定义宏常量
3)编译控制中,只许使用ifndef,不许使用ifdef
4)除了编译控制外,一切可以不用宏解决的地方,都不要用宏
例外:无
8,指针和堆对象
必须:1)指针的书写形式,* 符号要和指针的提领类型连在一起不留空白,而不是和指针对象连在一起。例子:
int* i; //推荐的写法
int *i; //禁止的写法
2)用new,delete,不用malloc, free
3)如果堆对象的分配和释放不能同步,那么必须用std::shared_ptr来替代原生指针
4)使用nullptr来表示空指针,禁用NULL
推荐:尽量使用std::shared_ptr来持有堆对象,使用RAII机制来回收资源
例外: 对于 必须2)和 必须3),在和c语言接口的地方可以存在例外
9,异常处理
必须:不可以用异常处理来实现程序逻辑分支跳转的功能,即不可用异常机制来实现if的功能
推荐:用异常来表示函数出错,而不是返回状态码。
例外:对于必须,无例外;对于推荐,在对性能极度敏感的地方可以例外
10,类
必须:1)non-static 数据成员的命名格式:m_变量名
2)static 数据成员的命名格式:M_变量名
3)使用成员初始化列表或默认值的方式对成员进行初始化,禁止在构造函数内用赋值语句来初始化,禁止在构造函数中使用memset(this, 0, sizeof(this))或类似方式来做对象初始化
4)成员函数先声明,数据成员后声明
5)对可能const的成员函数,一律声明为const
6)派生类重写基类虚函数时,函数声明中禁止带virtual,且必须带override
7)禁止出现hide的情况
8)禁止出现5层以上的继承体系
9)成员函数中用到类成员时,直接使用即可,禁用 this-> ,例子:
this->m_data.init(); //禁止
m_data.init(); //推荐
推荐:1)不要出现3层以上的继承体系,尽量少出现2层以上的继承体系
2)除非明确需要通过隐式类型转换来构造对象,构造函数一律带explicit
建议:1)用面向接口而非面向对象的思路来设计继承体系
2)少用继承
11,头文件
必须:1)禁止仅仅为了引入一个类型的声明(注意,是声明而非定义)而包含一个头文件,正确的做法是在需要的地方,自行声明
2)禁止头文件出现循环引用
3)头文件首部的编译控制宏的命名格式: 工程主文件夹下的路径_文件名
例子: 工程主文件夹 path/project,头文件路径 path/project/base/format.h
#ifndef BASE_FORMAT_H
#define BASE_FORMAT_H
#endif
推荐:尽量最小化头文件依赖,特别是在头文件需要包含头文件时
例外:无
12,命名规则
必须:1)禁用匈牙利命名法
2)禁止在代码中出现下述列表之外的字符 (当然,注释除外):
a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 _ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " ’
3)禁止以下滑线(_)作为名字的首字符,禁止连续使用两个或两个以上的下划线
4)namespace 的命名必须用纯小写, 规则同文件命名
5)类型的命名,包括通过class,struct,typedef,enum等一切方式定义的类型,一律以大写字母开头,每个单词的首字母大写
6)模板中的类型参数命名,规则同3)
7)对象的命名,一律以小写字母开头,除首单词外,每个单词的首字母大写
8)函数的命名,规则同4)
9)枚举值的命名:对于强类型枚举,使用普通的的驼峰命名法
10)常量的命名,全部大写,单词用下划线(_)分隔
11)文件名,纯小写,单词间用下划线分割
12)可以使用汉语拼音,但禁止使用汉语拼音缩写。
推荐:1)命名尽量清晰易懂,自注释
2)单个名字,最长不要超过64个字符
建议:1)同一个代码逻辑块儿内,如同一个类的声明或同一个函数的定义之内,汉语拼音和英文单词混用
2)在模板较复杂,泛化类型明显可以划分种类时,不要简单的使用T, X 之类的简单命名
例外:无
13,枚举类型
必须:1)必须为枚举类型指定对应的整形
2)禁止使用弱类型枚举
例子:
enum class Color : uint8_t {red, blue, yellow};
建议:尽量使用强类型枚举
例外:无
14,auto关键字
必须:1)在for循环中声明容器迭代器时可用auto
2)定义一个用lambda表达式直接初始化的仿函数对象时可用auto
3)定一个对象并直接显式的用其构造函数初始化时可用auto
4)其它一切情况下,禁用auto来声明对象
推荐:仅在阅读代码时,对理解auRED, BLUE, YELLOW};to代表的实际类型没有任何障碍的情况下,才用atuo
建议:除非有非常大的书写麻烦,否则尽量不用auto
例外:无
15,模板
必须:定义模板时,禁止用class声明类型参数,使用typename
建议:和非模板解决方案比,没有明显的优势时,慎用模板
例外:无
16,类型转换
必须:1)禁用c风格类型转换
2)禁用dynamic_cast
建议:尽量避免对纯数据类型做隐式类型转换
例外:无