C++ 为什么要将标题放在单独的目录中?

C++ 为什么要将标题放在单独的目录中?,c++,c,directory-structure,C++,C,Directory Structure,我知道,在C/C++项目中,将头文件放在一个目录(如include)中,并将实现放在一个单独的目录(如src)中是很常见的。我一直在玩弄不同的项目结构,我想知道这是否有客观的原因,或者它只是一种惯例?它让你的文件夹结构更干净。头文件和源文件明显不同,用于不同的用途,因此将它们分开是有意义的。从这个角度来看,问题基本上与“为什么源文件和文档放在不同的文件夹中”相同?计算机对你在文件夹中放什么和不放什么高度不可知,文件夹在很大程度上只是一个方便的抽象,因为我们人类解析、存储和调用信息的方式 还有一个

我知道,在C/C++项目中,将头文件放在一个目录(如
include
)中,并将实现放在一个单独的目录(如
src
)中是很常见的。我一直在玩弄不同的项目结构,我想知道这是否有客观的原因,或者它只是一种惯例?

它让你的文件夹结构更干净。头文件和源文件明显不同,用于不同的用途,因此将它们分开是有意义的。从这个角度来看,问题基本上与“为什么源文件和文档放在不同的文件夹中”相同?计算机对你在文件夹中放什么和不放什么高度不可知,文件夹在很大程度上只是一个方便的抽象,因为我们人类解析、存储和调用信息的方式


还有一个事实是头文件仍然有用,即使在您构建了,即如果您正在构建库,而有人想要使用该库,他们需要的是头文件——而不是源文件——因此将这些头文件捆绑在一起——在
bin
include
中获取内容,而不必筛选
src
——要容易得多。

惯例是原因之一——大多数情况下,通过有效的抽象,您只关心接口,只需查看标题即可轻松实现

但这不是唯一的原因。如果您的项目是按模块组织的,那么您很可能需要在不同的模块中包含一些标题,并且希望您的include目录中没有其他“噪音”文件

此外,如果您计划重新分发模块,您可能希望隐藏实现细节。因此,您只提供头文件和二进制文件,而从一个文件夹中分发头文件,而不在其中包含任何其他文件,这更简单

还有一个我实际上更喜欢的替代方案——公共头放在一个单独的文件夹中(这些文件夹包含最小的接口-没有任何实现细节可见),私有头和实现文件是单独的(可能,但不一定,在单独的文件夹中)。

此外(有争议?)对于保持事物有序、对其他项目有用等等,有一个非常中立和客观的优势:编译时间


特别是,在一个包含大量文件的大型项目中,这取决于标题的搜索路径(.c/.cpp文件使用
#包括“headername.h”
,而不是
#include”。/../gfx/misc/something/headername.h“
,并且编译器传递了正确的参数以实现这一点)您大大减少了编译器在搜索正确标题时需要扫描的条目数。由于大多数编译器分别为每个编译的文件启动,因此它们需要读入include路径上的文件列表,并为每个编译的文件寻找正确的头。如果include路径上有一堆.c、.o和其他不相关的文件,则查找其中的include会相应地花费更长的时间。

简而言之,有几个原因:

  • 可维护代码
  • 代码设计良好且整洁
  • 更快的编译时间(有时,对于较小的更改)
  • 更容易分离文档等接口
  • 可以避免编译时的循环依赖
  • 容易复习

看看这篇文章,它解释得很好。

我更喜欢把它们放在同一个目录中。原因:

接口规范文件和实现该接口的源文件属于项目的同一部分。假设您有
子系统x
。然后,如果将
subsystemx
文件放在
subsystemx
目录中,
subsystemmx
是自包含的

如果有很多include文件,当然你可以做
subsystemx/include
subsystemx/source
,但是我认为如果你把
class Foo
的定义放在
Foo.hpp
Foo.cpp
中,你肯定想看到这两个文件(或者至少可以很容易地做到这一点)一起放在一个目录列表中。查找与
foo相关的所有文件

ls foo*
查找所有实现文件:

ls *.cpp
ls *.hpp
查找所有声明文件:

ls *.cpp
ls *.hpp

简单明了。

这也许可以解释一下:或者可能是这样:我曾经有三个数学库项目的位置:src/for.c、include/for internal.h和api/for the.h,用于外部使用,用于使用库的应用程序。我甚至试着通过将它们命名为.API来区分面向公众的API头,但这混淆了工具链。这是用于
c
,但可能会有所帮助:你能解释一下这种分离是如何降低循环依赖的风险的吗?我很确定@parasrish回答了一个不同的问题“为什么要将头分离到单独的文件中?”但子系统之外的代码需要使用公共接口,因此公共接口头需要简单且可控地访问。如果您必须猜测子系统X的哪些头文件仅供内部使用,哪些头文件供外部使用,以及哪些头文件定义了API,那么您能想象这样的混乱吗?私有头可以与源代码共存,这没有问题。但是消费者需要的公共标题——这些标题需要以一种更受控制的方式提供。@JonathanLeffler我设计的是这样就没有私有标题了。包含“subsystemx/foo.hpp”
总是有意义的。如果有内部细节,我会将它们隐藏在实现文件中。另外,您如何确定头文件仅供私人使用?您很幸运能够在这样小的系统上工作。@JonathanLeffler如果您需要私人头文件,请在文件名中添加后缀
\u internal
。我同意这种方法。也有