google code style ---2.头文件

原文链接:https://google.github.io/styleguide/cppguide.html

第二章

  • 头文件
    • 头文件保护符【guard】
    • 前向声明
    • 内联函数
    • include 顺序

2.0 前言


       通常,每一个.cc文件都应有相关的【associated】.h 文件。当然会有一些例外【exceptions】,例如单元测试和仅仅含有main函数的.cc文件。
       正确的使用头文件将对代码可读性,文件大小,性能产生很大的影响【make a huge difference to】。
       下面的规则将会带领你认识使用头文件所遇到的陷阱【pitfall】。

2.1 self-contained 头文件

2.2 头文件保护符【guard】


       所有的头文件都应含有#define保护,用来防止多重引入【multiple inclusion】,标识符的命名格式应为

<PROJECT><PATH><FILE>_ H_

      为了保证唯一性【uniqueness】,标识符的命名应根据项目源文件所在的全路径。例如,文件/scr/bar/baz.h位于项目foo下,则该头文件应有下面的头文件保护符。

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

说明:第二种方法:#pragma once

2.3 前向声明


避免使用前向声明,取而代之的是使用#include引入需要的头文件。

2.4 内联函数

      当函数为10行或者低于10行,可以定义该函数为内联函数。
定义:
      可以声明函数为内联函数,从而允许编译器通过内联扩展,而不是像通常函数那样进行调用。

优点:
      内联函数可以生成更高效的目标代码,只要被内联的函数足够的小巧。放心的去内联accessors,mutators,以及其他小巧的重要的性能函数【通常为set和get方法】。

缺点:
       过度【overuse】的使用内联可能会导致程序变慢。根据函数大小的不同,内联可能会导致代码增加或者较少,内联accessor函数通常将会减少代码的大小,如果内联一个很大的函数,将显著【dramatically】增加代码的大小。因为更好的使用指令缓存【instruction cache】,现代的处理器在运行更少的代码将会更快。

结论:
      经验1:一个比较好【decent】的经验是低于10行的函数可以将其内联。特别注意析构函数,因为隐式的成员和调用基类析构函数,所以析构函数实际上要比看起来要长。

      经验2:通常【typically】不要内联带有loop或者是switch语句,除非大多数情况下,它们不会被执行【excuted】。
      虽然将一个函数定义为内联函数,但是这些函数通常不会被内联。例如,虚函数和递归函数通常不会被内联。通常递归函数不应该【should not】被内联.最主要的原因将虚函数放到类的定义中,是为了方便【convenience】或者为了记录他们的行为,如accessors和mutators.

注:在使用虚函数内联需要注意以下几点:
      1.虚函数可以是内联函数,内联可以修饰虚函数的,但是当虚函数表现多态性的时候,不能进行内联。
      2.inline virtual 唯一可以内联的时候是:编译器知道所调用的对象属于哪个类,如Base::who(),这只有在编译器具有实际对象而不是对象的指针或者引用的时才会发生。
代码示例

2.5 include顺序


       按照如下的包含头文件顺序:相关的头文件,C系统头文件,C++标准库头文件,其他库头文件,该项目头文件。

       所有的项目头文件应按照项目的目录树进行排列,并且避免使用UNIX目录别名,如(.当前目录),(…父目录)。例如:google-awesome-project/src/base/logging.h应该包含:

#include “base/logging.h”

       文件dir/foo.cc或者dir/foo_test.cc,两者的目的是实现或者测试dir2/foo2.h中的函数,包含的头文件应为:

1.dir2/foo2.h
2.空行
3.C 系统头文件(更确切的说,使用<>包含以.h结尾的文件)如:<unistd.h>,<stdlib.h>
4.空行
5.C++标准库头文件(不需要扩展名)如:<algorithm>,<cstddef>
6.空行
7.别的库.h文件
8.自己本身库.h文件

       使用空行将每一个非空的组分开。

       使用上述顺序,如果相关的头文件dir2/foo2.h遗漏【omits】任何必要的包含文件,则文件dir/foo.cc或者dir/foo_test.cc的build过程会崩溃【break】.因此这个规则保证了,如果build过程崩溃一定是目前的工作文件出现了问题,而不是别的包。

       dir/foo.cc和dir2/foo2.h通常在同一个目录下(如,base/basictypes_test.cc和base/basictypes.h),但是通常也可能不在同一个目录下。

       注意C头文件(如,stddef.h)基本上【essentially】都是可以与C++系统头文件(cstdef)交换的【interchangeable】。两种风格都是可以接受的,但是更倾向于和当前的代码库相一致【consistency】.

       包含的头文件中,每一组都应该按照字母表顺序【alphabetically】进行排列,注意如果以往的代码可能没有遵循这个规则,如果在方便的时候可以将其修改。
       应该包含所有的依赖的头文件,前向声明除外(但是该特性不太建议使用),如果依赖bar.h中的标识【symbol】,如果还依赖于foo.h,不要因为bar.h中已经依赖了foo.h就不去依赖他。除非foo.h明确的【explicitly】显示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”

例外:在特定系统【system-specific】的代码中需要条件包含【conditional includes】,条件包含的代码应该放在其他包含文件后面,当然特定平台的代码需要尽量的小巧,独立。

#include “foo/public/fooserver.h”

#include “base/port.h”

#ifdef  LANG_CXX11
#include <initializer_list>
#endif  // LANG_CXX11
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章