
Google C++ 风格指南-中文版.pdf
45页Google C++ 风格指南 - 中文版Google C++ 风格指南 - 中文版版本:版本:3.133原作者:原作者:Benjy Weinberger Craig SilversteinGregory Eitzmann Mark MentovaiTashana Landray翻译:翻译:YuleFox yospaly项目主页:项目主页:Google Style Guide Google 开源项目风格指南 - 中文版目录目录ContentsContentsGoogle C++ 风格指南 - 中文版 目录译者前言 背景1. 头文件1.1. #define 保护1.2. 头文件依赖 1.3. 内联函数1.4. -inl.h文件 1.5. 函数参数的顺序1.6. #include 的路径及顺序译者 (YuleFox) 笔记2. 作用域2.1. 名字空间2.1.1. 匿名名字空间 2.1.2. 具名的名字空间2.2. 嵌套类 2.3. 非成员函数, 静态成员函数, 和全局函数2.4. 局部变量 2.5. 静态和全局变量 译者 (YuleFox) 笔记3. 类3.1. 构造函数的职责 3.2. 默认构造函数3.3. 显式构造函数 3.4. 拷贝构造函数3.5. 结构体 VS. 类 3.6. 继承3.7. 多重继承 3.8. 接口3.9. 运算符重载 3.10. 存取控制3.11. 声明顺序 3.12. 编写简短函数 译者 (YuleFox) 笔记4. 来自 Google 的奇技4.1. 智能指针 4.2. cpplint5. 其他 C++ 特性 5.1. 引用参数5.2. 函数重载 5.3. 缺省参数5.4. 变长数组和 alloca() 5.5. 友元5.6. 异常 5.7. 运行时类型识别5.8. 类型转换 5.9. 流5.10. 前置自增和自减 5.11. const 的使用5.12. 整型 5.13. 64 位下的可移植性5.14. 预处理宏 5.15. 0 和 NULL5.16. sizeof 5.17. Boost 库6. 命名约定6.1. 通用命名规则6.2. 文件命名 6.3. 类型命名6.4. 变量命名 6.5. 常量命名6.6. 函数命名 6.7. 名字空间命名6.8. 枚举命名 6.9. 宏命名6.10. 命名规则的特例 7. 注释7.1. 注释风格 7.2. 文件注释7.3. 类注释 7.4. 函数注释7.5. 变量注释 7.6. 实现注释7.7. 标点, 拼写和语法 7.8. TODO 注释 译者 (YuleFox) 笔记8. 格式8.1. 行长度 8.2. 非 ASCII 字符8.3. 空格还是制表位 8.4. 函数声明与定义8.5. 函数调用 8.6. 条件语句8.7. 循环和开关选择语句 8.8. 指针和引用表达式8.9. 布尔表达式 8.10. 函数返回值8.11. 变量及数组初始化 8.12. 预处理指令8.13. 类格式 8.14. 初始化列表8.15. 名字空间格式化 8.16. 水平留白8.17. 垂直留白 译者 (YuleFox) 笔记9. 规则特例9.1. 现有不合规范的代码9.2. Windows 代码 10. 结束语译者前言译者前言Google 经常会发布一些开源项目, 意味着会接受来自其他代码贡献者的代码. 但是如果代码贡献者的编程风格与 Google 的不一致, 会给代码阅读者和其他代码提交这造成不小的困扰. Google 因此发布了这份自己的编程风格, 使所有提交代码的人都能获知 Google 的编程风格.翻译初衷:规则的作用就是避免混乱. 但规则本身一定要权威, 有说服力, 并且是理性的. 我们所见过的大部分编程规范, 其 内容或不够严谨, 或阐述过于简单, 或带有一定的武断性.Google 保持其一贯的严谨精神, 5 万汉字的指南涉及广泛, 论证严密. 我们翻译该系列指南的主因也正是其严 谨性. 严谨意味着指南的价值不仅仅局限于它罗列出的规范, 更具参考意义的是它为了列出规范而做的谨慎权 衡过程.指南不仅列出你要怎么做, 还告诉你为什么要这么做, 哪些情况下可以不这么做, 以及如何权衡其利弊. 其他团队未必要完全遵照指南亦步亦趋, 如前面所说, 这份指南是 Google 根据自身实际情况打造的, 适用于其主导的 开源项目. 其他团队可以参照该指南, 或从中汲取灵感, 建立适合自身实际情况的规范.我们在翻译的过程中, 收获颇多. 希望本系列指南中文版对你同样能有所帮助.我们翻译时也是尽力保持严谨, 但水平所限, bug 在所难免. 有任何意见或建议, 可与我们取得联系.中文版和英文版一样, 使用 Artistic License/GPL 开源许可.中文版修订历史:2009-06 3.133 : YuleFox 的 1.0 版已经相当完善, 但原版在近一年的时间里, 其规范也发生了一些变 化.yospaly 与 YuleFox 一拍即合, 以项目的形式来延续中文版 : Google 开源项目风格指南- 中文版项目.主要变化是同步到 3.133 最新英文版本, 做部分勘误和改善可读性方面的修改, 并改进排版效果. yospaly 重新翻修, YuleFox 做后续评审.2008-07 1.0 : 出自 YuleFox 的 Blog, 很多地方摘录的也是该版本.背景背景C++ 是 Google 大部分开源项目的主要编程语言. 正如每个 C++ 程序员都知道的, C++ 有很多强大的特性, 但这 种强大不可避免的导致它走向复杂,使代码更容易产生 bug, 难以阅读和维护.本指南的目的是通过详细阐述 C++ 注意事项来驾驭其复杂性. 这些规则在保证代码易于管理的同时, 高效使用C++ 的语言特性.风格, 亦被称作可读性, 也就是指导 C++ 编程的约定. 使用术语 “风格” 有些用词不当, 因为这些习惯远不止源代码文件格式化这么简单.使代码易于管理的方法之一是加强代码一致性. 让任何程序员都可以快速读懂你的代码这点非常重要. 保持统一编 程风格并遵守约定意味着可以很容易根据 “模式匹配” 规则来推断各种标识符的含义. 创建通用, 必需的习惯用语和模式可以使代码更容易理解. 在一些情况下可能有充分的理由改变某些编程风格, 但我们还是应该遵循一致性原 则,尽量不这么做.本指南的另一个观点是 C++ 特性的臃肿. C++ 是一门包含大量高级特性的庞大语言. 某些情况下, 我们会限制甚 至禁止使用某些特性. 这么做是为了保持代码清爽, 避免这些特性可能导致的各种问题. 指南中列举了这类特性, 并解释为什么这些特性被限制使用.Google 主导的开源项目均符合本指南的规定.注意: 本指南并非 C++ 教程, 我们假定读者已经对 C++ 非常熟悉.1. 头文件1. 头文件通常每一个 .cc 文件都有一个对应的 .h 文件. 也有一些常见例外, 如单元测试代码和只包含 main() 函数的 .cc 文件.正确使用头文件可令代码在可读性、文件大小和性能上大为改观.下面的规则将引导你规避使用头文件时的各种陷阱.1.1. #define 保护1.1. #define 保护TipTip所有头文件都应该使用 #define 防止头文件被多重包含, 命名格式当是: ___H_为保证唯一性, 头文件的命名应该依据所在项目源代码树的全路径. 例如, 项目 foo 中的头文件 foo/src/bar/baz.h 可按如下方式保护:#ifndef FOO_BAR_BAZ_H_ #define FOO_BAR_BAZ_H_ … #endif // FOO_BAR_BAZ_H_1.2. 头文件依赖1.2. 头文件依赖TipTip能用前置声明的地方尽量不使用 #include.当一个头文件被包含的同时也引入了新的依赖, 一旦该头文件被修改, 代码就会被重新编译. 如果这个头文件又包含了其他头文件, 这些头文件的任何改变都将导致所有包含了该头文件的代码被重新编译. 因此, 我们倾向于减少包含头文件, 尤其是在头文件中包含头文件.使用前置声明可以显著减少需要包含的头文件数量. 举例说明: 如果头文件中用到类 File, 但不需要访问 File 类的声明, 头文件中只需前置声明 class File; 而无须 #include “file/base/file.h“.不允许访问类的定义的前提下, 我们在一个头文件中能对类 Foo 做哪些操作?我们可以将数据成员类型声明为 Foo * 或 Foo 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数.(YuleFox 注: 递归调用堆栈的展开并不像循环那么简单, 比如递归层数在编译时可能是未知的, 大多数编译器都不支持内联递归函数). 虚函数内联的主要原因则是想把它的函数体放在类定义内, 为了图个方便, 抑或是当作文档描述其行为, 比如精短的存取函数.1.4. -inl.h文件1.4. -inl.h文件TipTip复杂的内联函数的定义, 应放在后缀名为 ‐inl.h 的头文件中.内联函数的定义必须放在头文件中, 编译器才能在调用点内联展开定义. 然而, 实现代码理论上应该放在 .cc 文件中, 我们不希望 .h 文件中有太多实现代码, 除非在可读性和性能上有明显优势.如果内联函数的定义比较短小, 逻辑比较简单, 实现代码放在 .h 文件里没有任何问题. 比如, 存取函数的实现理所当然都应该放在类定义内. 出于编写者和调用者的方便, 较复杂的内联函数也可以放到 .h 文件中, 如果你觉得这样会使头文件显得笨重, 也可以把它萃取到单独的 ‐inl.h 中. 这样把实现和类定义分离开来, 当需要时包含对应的 ‐inl.h 即可。
‐inl.h 文件还可用于函数模板的定义. 从而增强模板定义的可读性.别忘了 ‐inl.h 和其他头文件一样, 也需要 #define 保护.1.5. 函数参数的顺序1.5. 函数参数的顺序TipTip定义函数时, 参数顺序依次为: 输入参数, 然后是输出参数.C/C++ 函数参数分为输入参数, 输出参数, 和输入/输出参数三种. 输入参数一般传值或传 const 引用, 输出参数或输入/输出参数则是非-const 指针. 对参数排序时, 将只输入的参数放在所有输出参数之前. 尤其是不要仅仅因为是新加的参数, 就把它放在最后; 即使是新加的只输入参数也要放在输出参数.这条规则并不需要严格遵守. 输入/输出两用参数 (通常是类/结构体变量) 把事情变得复杂, 为保持和相关函数的一致性, 你有时不得不有所变通.1.6. 1.6. #include 的路径及顺序 的路径及顺序TipTip使用标准的头文件包含顺序可增强可读性, 避免隐藏依赖: C 库, C++ 库, 其他库的 .h, 本项目内的 .h.项目内头文件应按照项目源代码目录树结构排列, 避免使用 UNIX 特殊的快捷目录 . (当前目录) 或 .. (上级目录). 例如, google‐awesome‐project/src/base/logging.h 应该按如下方式包含:#include “base/logging.h” 又如, dir/foo.cc 的主要作用是实现或测试 dir2/foo2.h 的功能, foo.cc 中包含头文件的次序如下:dir2/foo2.h (优先位置, 详情如下)1.C 系统文件2.C++ 系统文件3.其他库的 .h 文件4.本项目内 .h 文件5.Page 2 of 31. 头文件 — Google C++ Style Guide2013-1-5file://D:\新建文件夹 (2)\zh-google-cpp-styleguide\headers.html这种排序方式可有效减少隐藏依赖. 我们希望每一个头文件都是可被独立编译的 (yospaly 译注: 即该头文件本身已包含所有必要的显式依赖), 最简单的方法是将其作为第一个 .h。