Google C++ Style----头文件

转载请注明出处<http://blog.csdn.net/qianqin_2014/article/details/51354434>

一、头文件

通常,每一个.cc 文件(C++的源文件)都有一个对应的.h 文件(头文件),也有一些例 外,如单元测试代码和只包含 main()的.cc 文件。

正确使用头文件可令代码在可读性、文件大小和性能上大为改观。 下面的规则将引导你规避使用头文件时的各种麻烦。

1. #define 的保护

所有头文件都应该使用#define 防止头文件被多重包含(multiple inclusion),命名格式当是:<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_

2. 头文件依赖

使用前置声明(forward declarations)尽量减少.h 文件中#include 的数量。

当一个头文件被包含的同时也引入了一项新的依 赖( dependency),只要该头文件被修改 , 代码就要重新编译。如果你的头文件包含了其他头文件,这些头文件的任何改变也将导致那 些包含了你的头文件的代码重新编译。因此,我们宁可尽量少包含头文件,尤其是那些包含 在其他头文件中的。

使用前置声明可以显著减少需要包含的头文件数量。举例说明:头文件中用到类File,但不需要访问File的声明,则头文件中只需前置声明 class File;无需#include "file/base/file.h"。

在头文件如何做到使用类 Foo 而无需访问类的定义?

  • 将数据成员类型声明为 Foo *或 Foo &;
  • 参数、返回值类型为 Foo 的函数只是声明(但不定义实现);
  • 静态数据成员的类型可以被声明为 Foo,因为静态数据成员的定义在类定义之外。

另一方面,如果你的类是 Foo 的子类,或者含有类型为 Foo 的非静态数据成员,则必须为之包含头文件。

有时,使用指针成员(pointer members,如果是 scoped_ptr 更好)替代 对象 成员(object members)的确更有意义。然而,这样的做法会降低代码可读性及执行效率。如果仅仅为了少包含头文件,还是不要这样替代的好。

当然,.cc 文件无论如何都需要所使用类的定义部分,自然也就会包含若干头文件。 译者注:能依赖声明的就不要依赖定义。

注释:

于是在VC下做了下测试,先自行建立Foo.h,Foo.cpp文件,里面定义一个类CFoo,不用管怎么定义,随便都行,然后建议main.cpp,在里面测试:

class CFoo;
class test
{
public:
    /*1*/ CFoo func(CFoo foo);//ok
    /*2*/ static CFoo sub;//ok
    /*3*/ CFoo& foo1;//ok
    /*4*/ CFoo* pfoo1;//ok
    /*5*/ CFoo foo; //error
};

之前都是直接include Foo.h 文件,这次不引用,而是声明一下CFoo类。下面看test类的声明。

1、正确。说明了规范中第2点,函数参数和返回值只是声明。

2、正确。说明了规范中第3点,静态数据成员的类型可以被声明为Foo,因为静态数据成员的定义在类定义之外。

3、4、正确。

5错误。说明了规范中第1点,非静态的数据成员必须是指针或引用,否则需要依赖定义,其实也好理解,非静态表示每个实例都占有内存,必然需要知道内存的大小,没有定义怎么能知道呢?

3. 内联函数

只有当函数只有 10 行甚至更少时才会将其定义为内联函数(inline function)。

定义(Definition):当函数被声明为内联函数之后,编译器可能会将其内联展开,无需按通常的函数调用机制调用内联函数。

优点:当函数体比较小的时候,内联该函数可以令目标代码更加高效。对于存取函数(accessor、mutator)以及其他一些比较短的关键执行函数。

缺点:滥用内联将导致程序变慢,内联有可能是目标代码量或增或减,这取决于被内联的函 数的大小。内联较短小的存取函数通常会减少代码量,但内联一个很大的函数(译者注:如 果编译器允许的话)将戏剧性的增加代码量。在现代处理器上,由于更好的利用指令缓存(instruction
cache),小巧的代码往往执行更快。

结 论:一个比较得当的处理规则是,不要内联超过 10 行的函数。对于析构函数应慎重对待 , 析构函数往往比其表面看起来要长,因为有一些隐式成员和基类析构函数(如果有的话)被调用!

另一有用的处理规则:内联那些包含循环或 switch 语句的函数是得不偿失的,除非在大多数情况下,这些循环或 switch 语句从不执行。

重要的是,虚函数和递归函数即使被声明为内联的也不一定就是内联函数。通常,递归函数 不应该被声明为内联的(译者注:递归调用堆栈的展开并不像循环那么简单,比如递归层数 在编译时可能是未知的,大多数编译器都不支持内联递归函数)。析构函数内联的主要原因 是其定义在类的定义中,为了方便抑或是对其行为给出文档。

4. -inl.h 文件

复杂的内联函数的定义,应放在后缀名为-inl.h 的头文件中。

在头文件中给出内联函数的定义,可令编译器将其在调用处内联展开。然而,实现代码应完全放到.cc 文件中,我们不希望.h 文件中出现太多实现代码,除非这样做在可读性和效率上 有明显优势。

如果内联函数的定义比较短小、逻辑比较简单,其实现代码可以放在.h 文件中。例如,存取函数的实现理所当然都放在类定义中。出于实现和调用的方便,较复杂的内联函数也可以 放到.h 文件中,如果你觉得这样会使头文件显得笨重,还可以将其分离到单独的-inl.h 中。 这样即把实现和类定义分离开来,当需要时包含实现所在的-inl.h 即可。

-inl.h 文件还可用于函数模板的定义,从而使得模板定义可读性增强。 要提醒的一点是,-inl.h 和其他头文件一样,也需要#define 保护。

5. 函数参数顺序(Function Parameter Ordering)

定义函数时,参数顺序为:输入参数在前,输出参数在后。

C/C++函数参数分为输入参数和输出参数两种,有时输入参数也会输出(译者注:值被修改时)。输入参数一般传值或常数引用(const references),输出参数或输入/输出参数为非常量指针(non-const pointers)。对参数排序时,将所有输入参数置于输出参数之前。不要仅仅因为是新添加的参数,就将其置于最后,而应该依然置于输出参数之前。

这一点并不是必须遵循的规则,输入/输出两用参数(通常是类/结构体变量)混在其中,会 使得规则难以遵循。

6. 包含文件的名称及次序

将包含次序标准化可增强可读性、避免隐藏依赖(hidden dependencies,译者注:隐藏 依赖主要是指包含的文件中编译时),次序如下: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(优先位置,详情如下)
C 系统文件
C++系统文件
其他库头文件
本项目内头文件

这种排序方式可有效减少隐藏依赖,我们希望每一个头文件独立编译。最简单的实现方式是将其作为第一个.h 文件包含在对应的.cc 中。

dir/foo.cc 和 dir2/foo2.h 通常位于相同目录下(像 base/basictypes_unittest.cc 和base/basictypes.h),但也可在不同目录下。相同目录下头文件按字母序是不错的选择。

举 例 来 说 ,google-awesome-project/src/foo/internal/fooserver.cc 的包含次序如下:

#include "foo/public/fooserver.h" // 优先位置

#include <sys/types.h>
#include <unistd.h>

#include <hash_map>
#include <vector>

#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/public/bar.h"

注释:

<http://www.cnblogs.com/clever101/archive/2011/08/21/2147892.html>

转载请注明出处<http://blog.csdn.net/qianqin_2014/article/details/51354434>

时间: 2024-10-07 09:02:15

Google C++ Style----头文件的相关文章

google cpp style 头文件

1. self-contained 头文件应该自包含(独立,可以作为第一个头文件),以 .h 结尾 至于用来插入文本的文件,说到底它们并不是头文件,所以应以 .inc 结尾. 2. #define保护头文件 #define相当于一个标志,标志名格式:<PROJECT>_<PATH>_<FILE>_H_ 3. 前置声明 尽量避免使用.一般来说,前置声明弊大于利. 4. 内联函数 原则:仅内联不超过10行的函数. 5. include路径和顺序 路径:相对于项目根目录的路径

Makefile 自动生成头文件的依赖关系 .

最近在看一本书<Windows游戏编程大师技巧> (Tricks of Windows Game Programming Gurus). 第一章给出了一个打砖块小游戏的示例程序. 包括三个文件: blackbox.h, blackbox.cpp和freakout.cpp (600行代码, 对于Windows C++程序来说还好, 没有让我freak out…). blackbox.cpp封装了部分DirectDraw, 提供了一些更傻瓜化的初始化DirectDraw, 画点, 画方框的工具函数

VS2015--win32工程配置的一些想法之Google Code Style中头文件的顺序

工程大了,有很多的头文件,也要引用很多的库文件. 从我们学习C++写hello world的那一刻起,就知道要包含一些系统文件. 那么顺序如何呢? 在review的时候,感觉自己写的东西就是一坨屎. 看看Google code style中是如何描述include文件顺序的: Names and Order of Includes Use standard order for readability and to avoid hidden dependencies: C library, C++

Google C++ style guide——头文件

1.#define保护 使用#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_ 2.头文件依赖 使用前置声明尽量降低.h文件里#include的数量. 头文件被更改时,须要又一次编译.那些包括了该头文件的代码也须要又一

google C++编程风格指南之头文件的包含顺序

google C++编程风格对头文件的包含顺序作出如下指示: (1)为了加强可读性和避免隐含依赖,应使用下面的顺序:C标准库.C++标准库.其它库的头文件.你自己工程的头文件.不过这里最先包含的是首选的头文件,即例如a.cpp文件中应该优先包含a.h.首选的头文件是为了减少隐藏依赖,同时确保头文件和实现文件是匹配的.具体的例子是:假如你有一个cc文件(linux平台的cpp文件后缀为cc)是google-awesome-project/src/foo/internal/fooserver.cc,

Google C++ Style Guide的哲学

Google C++ Style Guide并不是一个百科全书,也不是一个C++使用指南,但它描述适用于Google及其开源项目的编码指南,并不追求全面和绝对正确,也有许多人置疑它的一些规则.但作为一个最具影响力的编码规范,它里面有许多内容值得我们研究学习. 以下主要摘自GSG负责人Titus Winters在CppCon 2014上的演讲. 制订Google C++ Style Guide的目的 引导开发去做对的事,同时不易犯错. 哲学总结 关注于读者,而非作者 (Optimize for t

大型项目开发: 头文件顺序

经验告诉我们,某些编码实践虽然在C++中完全合法,但是绝对不能应用于大型项目环境中. 大型项目环境下必须有适当的约束,否则很容易变得难以控制并很难维护(摘自<<大规模C++程序设计>>).下面以Chromium中运用的两个Coding Style中定义的头文件顺序为例. 头文件顺序的差异 WebKit/Blink遵循业界标准的定义,其实也是Lakos在<<大规模C++程序设计>>中建议的顺序 : 编译单元对应的头文件 (Related header file

Google C++ style guide——C++类

1.构造函数的职责 构造函数中只进行那些没有实际意义的初始化,因为成员变量的"有意义"的值大多不在构造函数中确定. 可以的话,使用Init()方法集中初始化为有意义的数据. 优点:排版方便,无需担心类是否初始化. 缺点: 1)在构造函数中不易报告错误,不能使用异常: 2)操作失败会造成对象初始化失败,引起不确定状态: 3)构造函数内调用虚函数,调用不会派发到子类实现中,即使当前没有子类化实现,将来仍是隐患: 4)如果有人创建该类型的全局变量,构造函数将在main()之前被调用,有可能破

C++头文件的包含顺序研究

C++头文件的包含顺序研究 作者:朱金灿 来源:http://www.cnblogs.com/clever101 一.<Google C++ 编程风格指南>里的观点 最近公司在推行编码规范,领导提议基本上使用<Google C++ 编程风格指南>.其中<Google C++ 编程风格指南>对于头文件的包含顺序是这样的: Names and Order of Includes link ▽Use standard order for readability and to

分析caffe源码以及相应的Google c++ style

本人项目需分析caffe源码,并做一些相应的修改 1.caffe源码工程目录 src目录为整个工程的核心,它主要实现了神经网络的基本模型的组件:Blob.Layer.Net.Solver等核心类. include目录存放整个工程所有头文件. tools目录中存放了caffe的入口函数,用于参数解析,神经网络配置等. data目录和examples目录用于提供一些基本例子和相应数据. matlab和python目录存放用于两者的接口,只要不使用两者,目录下的内容没有实质作用. 其他一些目录和文件是