您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 销售管理 > Google_C++编程风格指南_中文版_3.133
GoogleC++编程风格指南译者前言Google经常会发布一些开源项目,意味着会接受来自其他代码贡献者的代码;但是如果代码贡献者的编程风格与Google的不一致,会给代码阅读者和其他代码提交这造成不小的困扰;Google因此发布了这份自己的编程风格,使所有提交代码的人都能获知Google的编程风格。翻译初衷:规则的作用就是避免混乱;但规则本身一定要权威,有说服力,并且是理性的;我们所见过的大部分编程规范,其内容或不够严谨,或阐述过于简单,或带有一定的武断性。Google保持其一贯的严谨精神,5万汉字的指南涉及广泛,论证严密;我们翻译该系列指南的主因也正是其严谨性;严谨意味着指南的价值不仅仅局限于它罗列出的规范,更具参考意义的是它为了列出规范而做的谨慎权衡过程。指南不仅列出你要怎么做,还告诉你为什么要这么做,哪些情况下可以不这么做,以及如何权衡其利弊;其他团队未必要完全遵照指南亦步亦趋,如前面所说,这份指南是Google根据自身实际情况打造的,适用于其主导的开源项目;其他团队可以参照该指南,或从中汲取灵感,建立适合自身实际情况的规范。我们在翻译的过程中,收获颇多;希望本系列指南中文版对你同样能有所帮助。我们翻译时也是尽力保持严谨,但水平所限,bug在所难免;有任何意见或建议,可与我们取得联系。中文版和英文版一样,使用ArtisticLicense/GPL开源许可。中文版修订历史:2009-063.133:YuleFox的1.0版已经相当完善,但原版在近一年的时间里,其规范也发生了一些变化。yospaly与YuleFox一拍即合,以项目的形式来延续中文版:Google开源项目风格指南-中文版项目;主要变化是同步到3.133最新英文版本,做部分勘误和改善可读性方面的修改,并改进排版效果;yospaly重新翻修,YuleFox做后续评审。2008-071.0:出自YuleFox的Blog,很多地方摘录的也是该版本。背景C++是Google大部分开源项目的主要编程语言;正如每个C++程序员都知道的,C++有很多强大的特性,但这种强大不可避免的导致它走向复杂,使代码更容易产生bug,难以阅读和维护。本指南的目的是通过详细阐述C++注意事项来驾驭其复杂性.这些规则在保证代码易于管理的同时,高效使用C++的语言特性.风格,亦被称作可读性,也就是指导C++编程的约定.使用术语“风格”有些用词不当,因为这些习惯远不止源代码文件格式化这么简单.使代码易于管理的方法之一是加强代码一致性.让任何程序员都可以快速读懂你的代码这点非常重要.保持统一编程风格并遵守约定意味着可以很容易根据“模式匹配”规则来推断各种标识符的含义.创建通用,必需的习惯用语和模式可以使代码更容易理解.在一些情况下可能有充分的理由改变某些编程风格,但我们还是应该遵循一致性原则,尽量不这么做.本指南的另一个观点是C++特性的臃肿.C++是一门包含大量高级特性的庞大语言.某些情况下,我们会限制甚至禁止使用某些特性.这么做是为了保持代码清爽,避免这些特性可能导致的各种问题.指南中列举了这类特性,并解释为什么这些特性被限制使用.Google主导的开源项目均符合本指南的规定.注意:本指南并非C++教程,我们假定读者已经对C++非常熟悉.1.头文件通常每一个.cc文件都有一个对应的.h文件.也有一些常见例外,如单元测试代码和只包含main()函数的.cc文件.正确使用头文件可令代码在可读性、文件大小和性能上大为改观.下面的规则将引导你规避使用头文件时的各种陷阱.1.1.#define保护Tip所有头文件都应该使用#define防止头文件被多重包含,命名格式当是:PROJECT_PATH_FILE_H_为保证唯一性,头文件的命名应该依据所在项目源代码树的全路径.例如,项目foo中的头文件foo/src/bar/baz.h可按如下方式保护:#ifndefFOO_BAR_BAZ_H_#defineFOO_BAR_BAZ_H_…#endif//FOO_BAR_BAZ_H_1.2.头文件依赖Tip能用前置声明的地方尽量不使用#include.当一个头文件被包含的同时也引入了新的依赖,一旦该头文件被修改,代码就会被重新编译.如果这个头文件又包含了其他头文件,这些头文件的任何改变都将导致所有包含了该头文件的代码被重新编译.因此,我们倾向于减少包含头文件,尤其是在头文件中包含头文件.使用前置声明可以显著减少需要包含的头文件数量.举例说明:如果头文件中用到类File,但不需要访问File类的声明,头文件中只需前置声明classFile;而无须#includefile/base/file.h.不允许访问类的定义的前提下,我们在一个头文件中能对类Foo做哪些操作?我们可以将数据成员类型声明为Foo*或Foo&.我们可以将函数参数/返回值的类型声明为Foo(但不能定义实现).我们可以将静态数据成员的类型声明为Foo,因为静态数据成员的定义在类定义之外.反之,如果你的类是Foo的子类,或者含有类型为Foo的非静态数据成员,则必须包含Foo所在的头文件.有时,使用指针成员(如果是scoped_ptr更好)替代对象成员的确是明智之选.然而,这会降低代码可读性及执行效率,因此如果仅仅为了少包含头文件,还是不要这么做的好.当然.cc文件无论如何都需要所使用类的定义部分,自然也就会包含若干头文件.1.3.内联函数Tip只有当函数只有10行甚至更少时才将其定义为内联函数.定义:当函数被声明为内联函数之后,编译器会将其内联展开,而不是按通常的函数调用机制进行调用.优点:当函数体比较小的时候,内联该函数可以令目标代码更加高效.对于存取函数以及其它函数体比较短,性能关键的函数,鼓励使用内联.缺点:滥用内联将导致程序变慢.内联可能使目标代码量或增或减,这取决于内联函数的大小.内联非常短小的存取函数通常会减少代码大小,但内联一个相当大的函数将戏剧性的增加代码大小.现代处理器由于更好的利用了指令缓存,小巧的代码往往执行更快。结论:一个较为合理的经验准则是,不要内联超过10行的函数.谨慎对待析构函数,析构函数往往比其表面看起来要更长,因为有隐含的成员和基类析构函数被调用!另一个实用的经验准则:内联那些包含循环或switch语句的函数常常是得不偿失(除非在大多数情况下,这些循环或switch语句从不被执行).有些函数即使声明为内联的也不一定会被编译器内联,这点很重要;比如虚函数和递归函数就不会被正常内联.通常,递归函数不应该声明成内联函数.(YuleFox注:递归调用堆栈的展开并不像循环那么简单,比如递归层数在编译时可能是未知的,大多数编译器都不支持内联递归函数).虚函数内联的主要原因则是想把它的函数体放在类定义内,为了图个方便,抑或是当作文档描述其行为,比如精短的存取函数.1.4.-inl.h文件Tip复杂的内联函数的定义,应放在后缀名为-inl.h的头文件中.内联函数的定义必须放在头文件中,编译器才能在调用点内联展开定义.然而,实现代码理论上应该放在.cc文件中,我们不希望.h文件中有太多实现代码,除非在可读性和性能上有明显优势.如果内联函数的定义比较短小,逻辑比较简单,实现代码放在.h文件里没有任何问题.比如,存取函数的实现理所当然都应该放在类定义内.出于编写者和调用者的方便,较复杂的内联函数也可以放到.h文件中,如果你觉得这样会使头文件显得笨重,也可以把它萃取到单独的-inl.h中.这样把实现和类定义分离开来,当需要时包含对应的-inl.h即可。-inl.h文件还可用于函数模板的定义.从而增强模板定义的可读性.别忘了-inl.h和其他头文件一样,也需要#define保护.1.5.函数参数的顺序Tip定义函数时,参数顺序依次为:输入参数,然后是输出参数.C/C++函数参数分为输入参数,输出参数,和输入/输出参数三种.输入参数一般传值或传const引用,输出参数或输入/输出参数则是非-const指针.对参数排序时,将只输入的参数放在所有输出参数之前.尤其是不要仅仅因为是新加的参数,就把它放在最后;即使是新加的只输入参数也要放在输出参数.这条规则并不需要严格遵守.输入/输出两用参数(通常是类/结构体变量)把事情变得复杂,为保持和相关函数的一致性,你有时不得不有所变通.1.6.#include的路径及顺序Tip使用标准的头文件包含顺序可增强可读性,避免隐藏依赖:C库,C++库,其他库的.h,本项目内的.h.项目内头文件应按照项目源代码目录树结构排列,避免使用UNIX特殊的快捷目录.(当前目录)或..(上级目录).例如,google-awesome-project/src/base/logging.h应该按如下方式包含:#include“base/logging.h”又如,dir/foo.cc的主要作用是实现或测试dir2/foo2.h的功能,foo.cc中包含头文件的次序如下:1.dir2/foo2.h(优先位置,详情如下)2.C系统文件3.C++系统文件4.其他库的.h文件5.本项目内.h文件这种排序方式可有效减少隐藏依赖.我们希望每一个头文件都是可被独立编译的(yospaly译注:即该头文件本身已包含所有必要的显式依赖),最简单的方法是将其作为第一个.h文件#included进对应的.cc.dir/foo.cc和dir2/foo2.h通常位于同一目录下(如base/basictypes_unittest.cc和base/basictypes.h),但也可以放在不同目录下.按字母顺序对头文件包含进行二次排序是不错的主意(yospaly译注:之前已经按头文件类别排过序了).举例来说,google-awesome-project/src/foo/internal/fooserver.cc的包含次序如下:#includefoo/public/fooserver.h//优先位置#includesys/types.h#includeunistd.h#includehash_map#includevector#includebase/basictypes.h#includebase/commandlineflags.h#includefoo/public/bar.h译者(YuleFox)笔记1.避免多重包含是学编程时最基本的要求;2.前置声明是为了降低编译依赖,防止修改一个头文件引发多米诺效应;3.内联函数的合理使用可提高代码执行效率;4.-inl.h可提高代码可读性(一般用不到吧:D);5.标准化函数参数顺序可以提高可读性和易维护性(对函数参数的堆栈空间有轻微影响,我以前大多是相同类型放在一起);6.包含文件的名称使用.和..虽然方便却易混乱,使用比较完整的项目路径看上去很清晰,很条理,包含文件的次序除了美观之外,最重要的是可以减少隐藏依赖,使每个头文件在“最需要编译”(对应源文件处:D)的地方编译,有人提出库文件放在最后,这样出错先是项目内的文件,头文件都放在对应源文件的最前面,这一点足以保证内部错误的及时发现了.2.作用域2.1.名字空间Tip鼓励在.cc文件内使用匿名名字空间.使用具名的名字空间时,其名称可基于项目名或相对路径.不要使用using关键字.定义:名字空间将全局作用域细分为独立的,具名的作用域,可有效防止全局作用域的命名冲突.优点:虽然类已经提供了(可嵌套的)命名轴线(YuleFox注:将命名分割在不同类的作用域内),名字空间在这基础上又封装了一层.举例来说,两个不同项目的全局作用域都有一个类Foo,这样在编译或运行时造成冲突.如果每个项目将代码置于不同名字空间中,project1::Foo和project2::Foo作为不同符号自然不会冲突.缺点:名字空间具有迷惑性,因为它们和类一样提供了额外的(可嵌套的)命名轴线.在头文件中使用匿名空间导致违背C++的唯一定义原则(OneDefinitionRule(ODR)).结论:根据下文将要提到的策略合理使用命名空间.2.1.1.匿名名字
本文标题:Google_C++编程风格指南_中文版_3.133
链接地址:https://www.777doc.com/doc-4131812 .html