Google的C ++样式指南。第2部分

第1部分。简介

第2部分。头文件

...





编写代码时,我们都使用代码格式化规则。有时会发明规则,而在其他情况下,则使用现成的样式指南。尽管所有C ++程序员都比本地人更容易阅读英语,但是在后者中拥有一本手册会更好。

本文是Google C ++样式指南的一部分翻译成俄语的内容。

原始文章(github上的fork),更新了翻译



头文件



希望每个.cc源文件都有一个匹配的.h头文件。此规则也有一些例外,例如单元测试或仅包含main()函数的小型.cc文件 头文件的正确使用会对代码的可读性,大小和性能产生巨大影响。 以下规则将帮助您避免头文件频繁出现问题。











独立头文件



头文件必须自给自足(就编译而言)并具有.h扩展名。打算包含在代码中的其他(非标头)文件必须具有.inc扩展名,并与包含代码配对。



所有头文件都应该是独立的。使用头文件时,用户和开发工具不应依赖特殊依赖项。头文件必须是可锁定的,并且必须包含所有必需的文件。



最好将模板和内联函数的定义及其声明放在同一文件中。这些定义必须包含在每个.cc中文件使用它们,否则某些构建配置上可能存在链接错误。如果声明和定义在不同的文件中,则其中一个应包括另一个。不要将定义分成单独的头文件(-inl.h)。以前,这种做法非常流行,现在是不可取的。



作为例外,如果从模板创建了模板参数的所有可用变体,或者模板仅实现了一个类使用的功能,则可以在一个(也只有一个).cc文件中定义该模板,并在其中使用该模板。



在极少数情况下,头文件不是自包含的。当文件包含在非标准位置(例如在另一个文件中间)时,可能会发生这种情况。在这种情况下,可能没有重新启用锁,并且也可能不包含其他头文件。使用.inc扩展名命名此类文件成对使用,并尝试尽可能满足一般要求。



重新启动锁



必须对所有头文件进行#define保护,以防止重新包含宏定义格式必须为:<PROJECT> _ <PATH> _ <FILE> _H_



为确保唯一性,请使用项目树中的完整文件路径组件。例如,foo项目中的文件foo / src / bar / baz.h可能具有以下锁定:



#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif  // FOO_BAR_BAZ_H_


初步公告



如果可能,请勿使用预先通知。的#include需要的头文件来代替



定义

“预声明”是没有相应定义的类,函数,模板的声明。







  • . #include ( ) .
  • . #include - .




  • , .
  • API, . , API: , , .
  • std:: .
  • , : #include. , #include ( ) :



          // b.h:
          struct B {};
          struct D : B {};
          // good_user.cc:
          #include "b.h"
          void f(B*);
          void f(void*);
          void test(D* x) { f(x); }  // calls f(B*)
          


    #include B D, test() f(void*).
  • , .
  • 允许进行初步声明(以及进一步使用指针作为类成员)的代码结构会使代码造成混乱和缓慢。


判决



  • 尽量避免预先声明在另一个项目中声明的实体。
  • 使用头文件中声明的函数时,请始终#include该文件。
  • 使用类模板时,最好#include其头文件。


另请参阅“名称”和“包含顺序”中的包含规则



内联函数



仅当函数较小(例如,不超过10行)时,才将函数定义为内联函数。



定义



除了标准的函数调用方式外,您还可以将函数声明为内联函数,并告诉编译器将其直接包含在调用代码中。



优点



使用内联函数可以生成更有效的代码,尤其是当函数较小时。将此功能用于获取/设置功能,其他简短和对性能至关重要的功能。



反对



内联函数的过度使用会使程序变慢。同样,内联函数根据其大小可以增加或减小代码的大小。如果这些功能很小,则可以缩小代码。如果函数很大,则代码大小会非常大。请注意,在现代处理器上,由于更好地使用了指令高速缓存,精简代码的运行速度更快。



判决



一个好的经验法则是不要把功能inlineable如果他们超过10行代码。避免使析构函数成为可内联的,因为它们可以隐式包含许多额外的代码:调用变量析构函数和基类!



另一个好的经验法则是,对于具有循环或switch语句的内联函数通常没有任何意义(除非在退化的情况下永远不会执行循环或其他语句)。



重要的是要了解,内联函数不一定会以这种方式编译为代码。例如,通常使用标准调用来编译虚函数和递归函数。通常,不应将递归函数声明为内联函数。进行内联虚拟函数的主要原因是将定义(代码)放在类定义本身中(以记录行为或可读性)-通常用于get / set函数。



名称和包含顺序



按照以下顺序插入头文件:配对文件(例如foo.h-foo.cc),C系统文件,C ++标准库,其他库以及您的项目文件。



所有项目标头必须相对于项目源目录,而不能使用UNIX别名(例如)(当前目录)或..(父目录)。例如,应该像这样包含google-awesome-project / src / base / logging.h



#include "base/logging.h"


另一个示例:如果dir / foo.ccdir / foo_test.cc文件的主要功能是实现并测试dir2 / foo2.h中声明的代码,则按以下顺序编写头文件:



  1. DIR2 / foo2.h
  2. C (: .h), <unistd.h>, <stdlib.h>.
  3. C++ ( ), <algorithm>, <cstddef>.
  4. .h .
  5. .h .


用空行分隔每个(非空)文件组。



当配对的头文件(dir2 / foo2.h)中缺少所需的头文件(系统等),并且对应的dir / foo.ccdir / foo_test.cc文件的组装失败时,此文件顺序使您能够检测到错误。结果,该错误将立即显示给使用这些文件的开发人员(而不是仅使用外部库的其他团队)。



通常,配对的文件dir / foo.ccdir2 / foo2.h位于同一目录中(例如,base / basictypes_test.ccbase / basictypes.h),尽管这不是必需的。



请注意,诸如stddef.h之类的C头文件通常可以与相应的C ++文件(cstddef互换。可以使用任何变体,但是最好遵循现有代码的样式。



在每个部分中,头文件最好按字母顺序列出。请注意,先前编写的代码可能不遵循此规则。如果可能(例如,更正文件时),请将文件的顺序更正为正确的顺序。



所有包含声明所需类型的头文件都应包括在内,但预先声明时除外。如果您的代码使用bar.h中的类型,请不要依赖另一个文件foo.h来包含bar.h并且您可以将自己限制为仅包含foo.h:显式包含bar.h(除非(在文档中可能已明确声明)foo.h也将为bar.h提供类型



例如,google-awesome-project /src/foo/internal/fooserver.cc中的头文件列表可能如下所示:



#include "foo/server/fooserver.h"
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/server/bar.h"


例外



在某些情况下,您需要根据预处理器的条件(例如,取决于所使用的OS)包括头文件。尝试使包含尽可能短(本地化),并将其放置在其他头文件之后。例如:



#include "foo/public/fooserver.h"
#include "base/port.h"  // For LANG_CXX11.
#ifdef LANG_CXX11
#include <initializer_list>
#endif  // LANG_CXX11


注意:



图片取自开源



All Articles