头文件
严格来说,每一个代码文件都应该包含对应的头文件,除了一些用于测试的或是只包含一个main函数的小文件。
自包含
头文件应该是自包含的(自己编译),并以结尾.h。
某些打算用来引用的非头文件类型的文件就要设置为.inc类型文件,这种文件要谨慎使用。
所有头文件都应该是独立的。用户和重构工具不必遵守特殊条件即可来引用头文件。具体来说,头文件应具有header-guard,并引用它需要的所有其他头文件。
最好将模板和内联函数的定义与其声明放置在同一文件中。这些构造的定义必须包含在每个使用它们的c++文件中,否则程序可能无法在某些链接配置中正确地链接。如果声明和定义在不同的文件中,则引用前者应传递地引用后者。不要将这些定义移动到单独包含的头文件中。
在极少数情况下,用来引用的文件可能不是自包含的。这些文件通常旨在包含在不寻常的位置,例如另一个文件的中间。他们可能不使用header-guard,也可能不引用其前置文件。这种情况下就要用.inc 扩展名命名此类文件。
#define Guard
所有头文件都应具有#define防护措施,以防止被多次引用。符号名称的格式应为 。
为了保证唯一性,它们应基于项目源代码树中的完整路径。例如,foo/src/bar/baz.h项目中的文件foo应具有以下防护:
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
…
#endif // FOO_BAR_BAZ_H_
只引用使用的文件
如果源文件或头文件引用了在其他地方定义的对象,则该文件应直接包含一个头文件,该头文件应适当地提供对应的声明或定义。除此情况之外,它就不应包含头文件。
不要依赖于传递性引用。这样编程这就就可以在不破坏代码的情况下从其头文件中删除不再需要的语句。这也适用于相关的头文件——就是说,假设foo.cpp使用了一个bar.h中定义的变量,那么foo.cpp也应引用bar.h,即使在它的头文件foo.h中已经引用过了bar.h。
前向声明
尽可能避免使用前向声明。相反,要引用需要的头文件。
“前向声明”是对没有关联定义的实体的声明。
优点:
- 前向声明可以节省编译时间,因为引用会迫使编译器打开更多文件并处理更多输入。
- 前向声明可以节省不必要的重新编译。#include由于标头中不相关的更改,s可能会迫使您的代码更频繁地重新编译。
缺点:
- 前向声明会隐藏依赖项,从而允许用户代码在标头更改时跳过必要的重新编译。
- 与#include语句相反的前向声明使自动工具难以发现定义该符号的模块。
- 对库的后续更改可能会破坏前向声明。函数和模板的前向声明可以防止头文件所有者对其API进行其他兼容的更改,例如扩展参数类型,添加具有默认值的模板参数或迁移到新的名称空间。
- 来自名称空间std::中的前向声明符号会产生未定义的行为。
- 可能难以确定究竟是是需要前向声明还是完整的引用。
内联函数
只在函数很小的情况下才能把它们定义为内联函数。(少于10行)
引用的名字及顺序
在引用时应当按以下顺序引用头文件:相关头文件,C系统头文件,C ++标准库头文件,其他库的头文件,项目的头文件。
项目的所有头文件都应列为项目源目录的子文件,而不使用UNIX目录别名。也就是((the current directory) 或 … (the parent directory)。
例如, 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.C系统头文件(更精确的是:带有.h扩展名的尖括号中的标头 ),例如<unistd.h>, <stdlib.h>。
3.空行
4.C ++标准库标头(无文件扩展名),例如 ,。
5.空行
6.其他库的.h文件。
7.您项目的.h 文件。
要用一个空行分隔每个非空组。