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

经验告诉我们,某些编码实践虽然在C++中完全合法,但是绝对不能应用于大型项目环境中。 大型项目环境下必须有适当的约束,否则很容易变得难以控制并很难维护(摘自<<大规模C++程序设计>>)。下面以Chromium中运用的两个Coding Style中定义的头文件顺序为例。

头文件顺序的差异

WebKit/Blink遵循业界标准的定义,其实也是Lakos在<<大规模C++程序设计>>中建议的顺序 :

  1. 编译单元对应的头文件 (Related header file)。
  2. 工程内的其它头文件。
  3. 库及系统头文件。

(Blink特殊的一点是编译单元必须先包含config.h。)

这样做的目的是为避免隐性依赖。每个头文件都应当做到自包含(Self-Contained, or Self Sufficient), 这样保证用户能直接头文件中理解它的物理依赖。如果遵循这个顺序,当出现隐性依赖时,是无法编译通过的。

下面这个例子:
my_class.h中依赖了std::string, 但没有显式的包含,当main里先包含标准库的头文件string时,编译是不会出错的。

main.cc

#include <string>
#include <iostream>
#include "my_class.h"

int main(int argc, char* argv[]) {
  MyClass aInstance;
  std::cout << aInstance.value() << std::endl;
}

my_class.h

#ifndef MY_CLASS_H_
#define MY_CLASS_H_
class MyClass {
 public:
  MyClass();
  const std::string& value();
 private:
  std::string value_;
};
#endif

如果遵循上面的规则,就会在编译main.cc时报错:

In file included from main.cc:1:
./my_class.h:6:9: error: use of undeclared identifier ‘std‘
  const std::string& value();

在一个层次更为清晰的项目下,错误最好归属到作者身上。这里main.cc做为my_class.h的用户,这样的错误最好由my_class.h的作者来解决。所以Google定义了如下的规则:
? 关联的头文件
? C库头文件
? C++库头文件
? 其它库头文件?* 项目中的其它头文件。
实现如下的my_class.cc时就会收到报错:?my_class.cc

#include "my_class.h"
#include <string>

MyClass::MyClass()
  :value_("Hello!") {
}

在这种情况下,这个错误将只报给my_class.h对应的编译单元my_class.cc。

In file included from my_class.cc:1:
./my_class.h:6:9: error: use of undeclared identifier ‘std‘
  const std::string& value();

如果是一个小项目,可能察觉不到这样做的差异。但在讲求职责清晰,分工协作的大型项目下,它就会变得很有价值。
这是一个很小的点,可见大型项目中一些规则定义的冰山一角。再比如大型项目中的头文件还有一些设计上的权衡。比如避免不必要包含头文件会拖慢项目的构建效率,引入了前置声明。但它却在一些场景下会造成歧义(比如前置声明标准库中的类,或者模板类),或者引入一些的维护成本和风险(比如函数的参数变化,需要对应修改前置声明)。Google早期是鼓励使用前置声明,而现在只是强调在明确带来好处的情况下才建议使用前置声明。

扩展阅读:

Self-sufficient header files in C/C++
Headers and Includes: Why and How
C/C++ include file order/best practices

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-22 15:25:20

大型项目开发: 头文件顺序的相关文章

大型项目开发: 隔离 (《大规模C++程序设计》书摘)

书中第六章 隔离. 主要在撰述什么须要定义在头文件?什么应当移到编译单元中? 核心仍然是先区分接口定义与实现细节.实现细节的改变会导致客户代码的又一次编译,从逻辑上也表示与客户代码间可能存在着强耦合. 实现细节与隔离 主要考察下面实现细节.它们会在接口中引入实现细节.也是须要考虑进行隔离的内容: 继承 分层 简单的说就是类的成员中有还有一个类的实例时,如Foo mFoo. 这个类就会依赖于Foo的定义.而转为持有地址时,即将关系从HasA改为HoldA时,就不存在这个问题.也就是定义为Foo*

iOS大型项目开发漫谈

标题有些吓人请不要害怕,不过这确实不是扫盲贴,需要一定的iOS开发基础.在我多年的码农生涯中绝大部分时间都是做的小项目,大一些的可能也就是百万行代码的样子,跟Windows系统几千万行源码比简直就是小巫见大巫.不过,一个iOS项目的源码有数百万行算蛮大了.我想说的是,人总是会成长,会担当更大的责任接受更大的挑战,终有一天组织会有重要任务交给你.不过软件开发不是一朝一夕,也不会有多么的轰轰烈烈,更多的是平淡中无数的细节处理.做大型项目未必就需要多么高深的技术,也许就是细节的科学处理与规范的管理.

iOS 大型项目开发漫谈

标题有些吓人请不要惧怕,不过这的确不是扫盲贴,需要必定的iOS开发根底.在我多年的码农生计中绝大部分时刻都是做的小项目,大一些的可能也即是百万行代码的姿态,跟Windows体系几千万行源码比几乎即是小巫见大巫.不过,一个iOS项目的源码稀有百万行算蛮大了.我想说的是,人老是会生长,会担任更大的职责接受更大的应战,终有一天安排会有主要任务交给你.不过软件开发不是一朝一夕,也不会有多么的轰轰烈烈,更多的是平平中很多的细节处理.做大型项目未必就需要多么深邃的技能,或许即是细节的科学处理与规范的管理.

CakeDC(cakephp company)Git workflow--适合于较大团队大型项目开发

CakeDC Git workflow是一个项目开发和版本发布的工作流,在这个工作流程中开发和版本发布周期是基于几个关键阶段(key phases): Development: 所有活跃的开发活动都由里程碑驱动,在这个阶段的产出是很不稳定的代码基线 QA: Quality assurance testing作为一开发周期的一部分,主要协助确保需求的满足性和质量的可接受性 Review 客户或者评审员面对的是一个稳定的代码基线,该基线已经经过了QA流程,质量上已经被QA人员认可 Release 发

Java大型项目开发(1):配置Dubbox

CentOS的配置: 1.给CentOS安装Zookeeper: 网络配置成仅主机 上传tar.gz:比如用FTP tar -xvzf ... cd zookeeper mkdir data cd conf mv zoo_sample.cfg zoo.cfg vi zoo.cfg 修改这一行: dataDir=/soft/zookeeper-3.4.6/data 然后就可以运行了: cd bin ./zkServer.sh start 下面做一个最基本的Demo,返回一个固定的名称即可: 服务提

Vue/Egg大型项目开发(二)数据库设计

项目其他的实现都好说,不过为了梳理好思路和架构首先要搞定数据库 设计 这里推荐使用processon.com,因为是个在线的作图平台可以很方便的和他人合作. 设计出数据表后,就可以使用sequelize来生成相应的orm对象,然后sync到数据库中从而生成对应的数据表. 数据表类图 这是我项目的设计图,后期可能还会有修改. sequelize定义对应的orm对象 在model文件夹中定义对应的orm对象 比如user.js中如下,值得注意的是我们添加了一些额外字段以应对后期表中字段的添加. 代码

怎么学习阅读大型项目的代码

第一章: 导论 ++++++++++++ 1.要养成一个习惯, 经常花时间阅读别人编写的高品质代码. 2.要有选择地阅读代码, 同时, 还要有自己的目标. 您是想学习新的模式|编码风格|还是满足某些需求的方法. 3.要注意并重视代码中特殊的非功能性需求, 这些需求也许会导致特殊的实现风格. 4.在现有的代码上工作时, 请与作者和维护人员进行必要的协调, 以避免重复劳动或产生厌恶情绪. 5.请将从开放源码软件中得到的益处看作是一项贷款, 尽可能地寻找各种方式来回报开放源码社团. 6.多数情况下,

如何阅读大型项目的代码?

本文转载自:http://blog.csdn.net/jk110333/article/details/7563718 Technorati 标签: 源码阅读 -------------------------------我是分割线的开始------------------------------------------ ++++++++++++++++++++ 第一章: 导论 ++++++++++++ 1.要养成一个习惯, 经常花时间阅读别人编写的高品质代码. 2.要有选择地阅读代码, 同时,

关于头文件的一道选择题

题目: 以下关于头文件,说法正确的是(B) A.#include,编译器寻找头文件时,会从当前编译的源文件所在的目录去找 B.#include“filename.h”,编译器寻找头文件时,会从通过编译选项指定的目录去找 C.多个源文件同时用到的全局整数变量,它的声明和定义都放在头文件中,是好的编程习惯 D.在大型项目开发中,把所有自定义的数据类型.全局变量.函数声明都放在一个头文件中,各个源文件都只需要包含这个头文件即可,省去了要写很多#include语句的麻烦,是好的编程习惯. 知识点: A.