头文件
- 所有头文件要能够自给自足。换言之,用户和重构工具不需要为特别场合而包含额外的头文件。
- 所有头文件都应该使用
#define
来防止头文件被多重包含, 命名格式当是:<PROJECT>_<PATH>_<FILE>_H_
. - 尽量避免前置声明那些定义在其他项目中的实体.函数:总是使用 #include.类模板:优先使用 #include.
- 只有函数少于10行时才是用内联。内联那些包含循环或 switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或 switch 语句从不被执行)。
- 使用标准的头文件包含顺序可增强可读性, 避免隐藏依赖: 相关头文件, C 库, C++ 库, 其他库的 .h, 本项目内的 .h.
作用域
- 鼓励在 .cc 文件内使用匿名命名空间或 static 声明. 使用具名的命名空间时, 其名称可基于项目名或相对路径. 禁止使用 using 指示(using-directive)。禁止使用内联命名空间(inline namespace)。
- 禁止使用类的 静态储存周期 变量:由于构造和析构函数调用顺序的不确定性,它们会导致难以发现的 bug ,只能使用都必须是原生数据类型 (POD : Plain Old Data): 即 int, char 和 float, 以及 POD 类型的指针、数组和结构体。完全禁用 vector (使用 C 数组替代) 和 string (使用 const char [])作为全局变量,他们的构造和析构顺序不定。
类
- 构造函数不许调用虚函数。如果构造失败,直接exit(),不然不好发现错误。如果需要的话,请用init()方式初始化。
- 不要定义隐式类型转换. 对于转换运算符和单参数构造函数, 请使用 explicit 关键字.
- 如果你的类型需要, 就让它们支持拷贝 / 移动. 否则, 就把隐式产生的拷贝和移动函数禁用.
- 仅当只有数据成员时使用 struct, 其它一概使用 class.
- 使用组合 (YuleFox 注: 这一点也是 GoF 在 <> 里反复强调的) 常常比使用继承更合理. 如果使用继承的话, 定义为 public 继承.
- override 关键字,可以避免派生类中忘记重写虚函数的错误
- 除少数特定环境外, 不要重载运算符. 也不要创建用户定义字面量.
- 所有按引用传递的参数必须加上 const.8所有按引用传递的参数必须加上 const.
c++奇怪的技巧
- 如果要传递所有权,使用shared_ptr。
- 不要使用缺省参数。
- 使用 C++ 的类型转换, 如 static_cast<>()
- i++会额外返回一次拷贝。
- 如果数字很大,使用size_t,不使用无符号值。大整数int64_t。
- 尽可能用 sizeof(varname) 代替 sizeof(type).
- auto 只能用在局部变量里用。别用在文件作用域变量,命名空间作用域变量和类数据成员里。永远别列表初始化 auto 变量。auto 还可以和 C++11 特性「尾置返回类型(trailing return type)」一起用,不过后者只能用在 lambda 表达式里。
- lamda表达式捕获的时候需要写明捕获谁。
命名约定
- 文件名要全部小写, 可以包含下划线 () 或连字符 (-), 依照项目的约定. 如果没有约定, 那么 “” 更好.
- 类型名称的每个单词首字母均大写, 不包含下划线
- 变量 (包括函数参数) 和数据成员名一律小写, 单词之间用下划线连接. 类的成员变量以下划线结尾, 但结构体的就不用.
- 不管是静态的还是非静态的, 类数据成员都可以和普通变量一样, 但要接下划线.
- 声明为 constexpr 或 const 的变量, 或在程序运行期间其值始终保持不变的, 命名时以 “k” 开头, 大小写混合。所有具有静态存储类型的变量 (例如静态变量或全局变量, 参见 存储类型) 都应当以此方式命名。
- 常规函数使用大小写混合, 取值和设值函数则要求与变量名匹配
- 枚举类当作常量处理(大小写混写)。
- 简短的条件语句允许写在同一行. 只有当语句简单并且没有使用 else 子句时使用:
- 构造函数初始化列表放在同一行或按四格缩进并排多行.