原文:http://zh-google-styleguide.readthedocs.org/en/latest/google-cpp-styleguide/contents/
源自Google 编码规范,按照自己的情况,给自己定一个标准
1.头文件
1.1.#define 保护
所有头文件都应该使用#define 防止头文件被多重包好,命名格式是:_<PROJECT>_<FILE>_H_
1.2.头文件依赖
能用前置声明的地方尽量不使用#include
原因:减少编译依赖
1.3.内联函数
只有当函数只有10行以下时彩将其定义为内联函数
特殊:析构函数包含隐式的代码,往往比看到的长,循环或switch函数不应该内联,递归函数和虚函数的内联命令往往会被忽略
1.5.函数参数顺序
顺序依次为: 输入参数,输入/输出参数,输出参数
2.作用域
2.1.命名空间
命名空间基于项目名,不要使用using
2.1.1匿名名字空间
在.cpp文件中,鼓励使用匿名名字空间替代static,不要在.h中使用匿名名字空间
2.2.嵌套类
当一个类只会被另一个类访问时,使用嵌套类,不要将嵌套类定义成公有
2.3.非成员函数、静态成员函数和全局函数
使用静态成员函数或名字空间内的非成员函数,尽量不要用裸的全局函数,如果只是在.cpp文件中调用,使用匿名命名空间
2.4.局部变量
将函数变量尽可能置于最小作用域内,并在变量声明时进行初始化,如果循环中的变量是一个对象,每次进出作用域都要进行构造,析构,那么移动到循环外
2.5.静态和全局变量
禁止使用class类型的静态或全局变量,只能是原生数据类型以及对应的数据/结构体/指针,不要使用函数返回值初始化静态变量(不理解),不要在多线程代码中使用非const的静态变量
3.类
3.1.构造函数的职责
构造函数只进行那么没什么意义的初始化,比如指针赋值null等,可能的话,使用Init()方法集中初始化有意义的数据(构造函数不能使用异常,构造函数失败会使对象进入不确定态,构造函数不应该调用虚函数)
3.2默认构造函数
如果一个类定义了若干成员变量(不包括父类中的变量)又没有其他构造函数,必须定义一个默认构造函数,把内部状态初始化成一致/有效的值,否则编译器将生成一个糟糕的默认构造函数,对对象进行不确定的初始化
3.3.显示构造函数
对单个参数的构造函数使用C++关键字explicit,防止对象隐式转换
3.4.拷贝构造函数
仅在代码中需要拷贝一个类对象的时候使用拷贝构造函数,大部分情况下都不需要,可以使用宏 DISALLOW_COPY_AND_ASSIGN
3.5.结构体VS.类
仅当只有数据时使用struct,其他都是用class,仿函数(functors)和特性(traits) 可以使用struct
3.6.继承
所有继承必须是public的,如果想使用私有继承,那么应该实现为成员对象
继承适用在is-a 组合适用在has-a
如果类中有虚函数,析构函数也应该是虚函数,数据成员在任何情况下都必须是私有的
重载一个虚函数,必须明确声明为virtual,使得阅读者判断是否是虚函数不用检查所有父类
3.7.多重继承
所有父类除第一个外都是纯接口类,才允许使用多重继承,这些类以I开头
3.8.接口
接口:
只有纯虚函数和静态函数(析构函数例外)
没有非静态数据成员
没有定义任何构造函数,如果有,也不能带有参数,并且必须为protected
如果他是一个子类,也只能从满足上述条件并以I为前缀的类继承
3.9.运算符重载
尽量不要使用运算符重载,除非使用一些STL算法
3.10.存取控制
将所有数据成员声明为private,并根据需要提供对应的存取函数,一般在头文件中定义为内联函数
3.11.声明顺序
类的访问控制字段声明顺序依次为:public protected private
每个区段内的声明通常按以下顺序:
typedefs 和枚举
常量
构造函数
析构函数
成员函数,含静态成员函数
数据成员,含静态数据成员
宏DISALLOW_COPY_AND_ASSIGN 的调用放在private区段的末尾
3.12.编写简单函数
如果函数超过40行,考虑在不影响程序结构的前提下对其进行分割,如果需要使用其中的一小段代码,考虑分割为更加简短并易于管理的若干函数
5.1.引用参数
输入参数是值参或const引用,输出参数为指针
5.2.函数重载
仅在输入参数类型不同,功能相同时使用重载函数(含构造函数),不要用重载函数模拟缺省参数,不要包含缺省参数(自己觉得)
5.3.缺省参数
不要使用缺省参数
5.4.变长数组和alloca()
不要使用变长数组和alloca()
5.5.友元
通常友元应该定义在同一文件内
5.6.异常
谷歌不推荐使用异常,我也不会用
5.7.运行时类型识别
不要使用RTTI
5.8.类型转换
使用static_cast替代C风格的值转换
用const_cast去掉const限定符
用reinterpret_cast 指针类型和整形,或其他指针间进行不安全的互相转化
dynamic_cast 除测试代码外,不要使用
5.9.流
使用printf和 scanf代替流
5.10.前置自增和自减
不考虑返回值的话,使用前置自增
5.11.const的使用
在任何可能的情况下都要使用const
5.12.整形
尽量不要使用unsigned类型,使用断言保护数据
5.14.预处理宏
尽量不要使用宏
5.15. 0和NULL
整数用0,实数用0.0 指针用NULL 字符(串)用'\0'
5.16. sizeof
尽量使用sizeof(varname) 代替sizeof(type),因为变量可能会在未来的编码中改变类型
6.1.通用命名规则
函数名,变量命名,文件命名,应具备描述性,不要过度缩写,类型和变量应该是名词,函数名可以用命令性动词,除非缩写在其他地方都非常普遍,否则不要使用
6.2.文件命名
文件名称的每个单词首字母均大写,不包含下划线
6.3.类型命名
变量命名一律使用小驼峰命名法,类型名称的每个单词首字母均大写,不包含下划线(类,结构体,类型定义,枚举)
6.4.变量命名
变量命名一律使用小驼峰命名法,类的成员变量加前缀m,如:
tableName
mTableName
6.5.常量命名
所有编译时常量,无论是局部的,全局的,还是类中的,都和其他变量稍微区别一下,k后接大写字母开头的单词,如:
const int kDaysInAWeek = 7;
6.6.函数命名
函数命名一律使用大驼峰命名法
6.8.枚举命名
枚举的命名和常量命名一致
6.9.宏命名
如:MY_MACRO_THAT_SCARES_SMALL_CHILDREN
7.3.类注释
每个类的定义都要附加一份注释,描述类的功能和用法
7.4.函数注释
函数声明处注释描述函数功能,定义处描述函数实现
函数声明:
注释位于声明之前,对函数功能及用法进行描述
注释内容:
函数的输入输出
对类成员函数而言:函数调用期间对象是否需要保持引用参数,是否会释放这些参数
如果函数分配了空间,需要由调用者释放
参数是否可以为NULL
是否存在函数使用上的性能隐患
如果函数是可重入的,其同步前提是什么?(多任务)
函数定义:
每个函数定义时要用注释说明函数功能和实现要点,不要从.h文件或其他地方复制注释
7.5.变量注释
如果变量可以接受NULL 或-1等警戒值,需加以说明
7.6.实现注释
对于代码中巧妙的,晦涩的,有趣的,重要的地方加以注释。
行注释:在比较隐晦的地方要在行尾加入注释,在行尾空两格进行注释
如果需要连续进行多行注释,可以使之对齐获得更好的可读性
向函数传入NULL,bool 或整数时,要注释说明含义
7.7.标点,拼写,和语法
注释的通常写法是包含正确大小写和结尾句号的完整语句
7.8.TODO注释
对那些临时的,短期的解决方案,或以为够好,但仍不完美的代码使用TODO注释
注释使用全大写的字符串TODO在随后的圆括号里写入身份标识
8.1.行长度
每一行代码字符数不超过80
特例
如果一行注释包含了超过80字符的命名或URL,出狱复制粘贴的方便允许该行超过80字符
包含长路径的#include 可以超出80行,但应该尽量避免
头文件保护可以无视该原则
8.2.非ASCII字符
谷歌推荐使用UTF-8编码,可是项目一般使用多字节
8.4.函数声明与定义
函数返回类型和函数名在同一行,参数也尽量放在同一行,如果同一行文本太多:
ReturnType ClassName::ReallyLongFunctionName(Type par_name1,
Type par_name2,
Type par_name3)
{
DoSomething();
...
}
8.5.函数调用
尽量放在同一行,将实参封装在圆括号中
如果同一行放不下,可断为多行,后面每一行都可以第一个实参对其
8.6.条件语句
在圆括号和条件之间,不要有空格
如果能增强可读性,简短短条件语句允许写一行,并使用{}包围,只有当语句简单并且没有使用else子句时使用
8.7.循环和switch语句
switch语句可以使用大括号分段,空循环应使用{}或continue
如果有不满足case条件的枚举值,switch应该总是包含一个default,如果default永远指向不到,简单的加条assert
8.8.指针和引用表达式
句点或箭头前后不要有空格,指针/地址操作符(*,&)之后不能有空格
声明指针变量或参数时,星号与类型紧挨
8.9.布尔表达式
如果布尔表达式超过标准行宽,断行方式要统一:
if (this_one_thing > this_other_thing &&
a_third_thing == a_fourth_thing &&
yet_another & last_one)
{
...
}
8.10.函数返回值
return 表达式中不要用圆括号包围
8.11.变量及数组初始化
用=或()均可
int x = 3;
int x(3);
string name("Some Name");
string name = "Some Name";
8.12.预处理指令
即使预处理指令位于缩进代码块中,指令也应该从行首开始
8.13.类格式
所有基类名应在80列限制下尽量与子类名放在同一行
关键词public protected private 要缩进1个空格,除了第一个关键词外,其他关键词前要空一行,关键词后不要留空行
8.14.初始化列表
8.15.名字空间格式化
名字空间内容不缩进
8.16.水平留白
水平留白的使用因地制宜,永远不要在行尾添加没意义的留白
8.17.垂直留白
垂直留白越少越好,使得同屏可以显示的代码越多