【问题标题】:Coding C++ (mostly) in header files vs .cpp files在头文件与 .cpp 文件中编码 C++(主要是)
【发布时间】:2012-04-23 14:11:14
【问题描述】:

多年来,我一直以标准方式编写 C++,在头文件 .hpp 中使用类声明,在源文件 .cpp 文件中使用函数定义。最近我搬到了一家新公司,那里的代码(似乎受 boost 编码风格的影响)完全编码在 .hpp 文件中,其中包含一个简短的 .cpp 文件来包含头文件并创建对象/程序二进制文件。

这让我开始思考 - 在头文件中编写代码而不是为每个对象编写 .hpp 和 .cpp 文件有哪些优势/劣势?这假设我们的项目没有创建 common 库然后链接到程序二进制文件,而是每个程序二进制文件都是从头文件(和一个源 .cpp 文件)的总和构建的。这是 C++ 的新趋势吗?

例如模板对象只需要是头文件,但将非模板类放入头文件中,然后简单地将这些常见的项目类包含在您的二进制文件中似乎是个好主意。假设您从头开始创建一个新的代码库,这是否意味着更少的链接,这可能意味着更少的链接错误和更快的构建速度。预编译的头文件设施是否也意味着使用头文件可以加快构建时间?还是因为我们现在需要在创建二进制文件而不是链接公共共享库对象时编译所有代码,所以构建时间更长?

另外请注意,我们不是在此处编写 API(在这种情况下,像 pimpl idiom 之类的东西会通过隐藏实现为我们提供更大的灵活性),我们正在编写在客户站点上运行的程序。

提前致谢,

【问题讨论】:

  • 更快的完整构建?我不知道。但是通过这个方案,你总是得到完整的构建。
  • 是的,完整构建是唯一的选择,因为唯一的源文件创建了最终的二进制文件

标签: c++ build


【解决方案1】:

在我的头顶:

优势:

  • 实现可见(更多的是一个弱点,但取决于具体情况)
  • 无需导出到库
  • 编译器有更好的机会优化部分代码

弱点:

  • 实现可见
  • 构建时间变慢
  • 头文件臃肿
  • 实现中的更改需要完全重建,而在实现文件中实现不需要(仅编译该特定文件或库)
  • 在循环依赖的情况下,您使用前向声明并且只在实现文件中包含完整类型。如果你只有一个标题,那就不可能了。

我确定还有其他的,如果我能想到更多,我会编辑。

【讨论】:

  • 你没有把优点和缺点混为一谈吗?此外,您可能想明确指出您所谈论的方法的优势/劣势?
  • @AmbrozBizjak 我有,只是注意到了。已编辑。
  • 感谢 Luchian 的回答,听起来人们不太热衷于在大型项目中将所有代码放在头文件中。
  • 你错过了关于“优势”的“很容易添加到项目中而无需跳过大量依赖构建箍”。当您在一个环境中工作时,这可能是一件大事余波,直到你早已离开。
【解决方案2】:

只有头文件的库往往使构建系统更容易,通常你不需要关心依赖关系。

另一方面,将代码移动到实现文件可以更轻松地控制模块边界并创建可交换的二进制模块,从而改进增量构建。成本更多的是“管家”。 我的直觉是更喜欢实现文件,并且有一些支持我的数据点,例如来自提议的 Boost Networking Library 的作者的this blog post

【讨论】:

  • +1 用于博客文章链接,很高兴知道我不是唯一一个考虑这种编码风格的人。
【解决方案3】:

通用库是一回事,代码的一般可重用性是另一回事。如果您想使用您在另一个项目中编写的一些代码,您可能必须复制'n'粘贴大量代码,然后维护单独的代码库。编译时间会变长,因为程序将是一个很大的编译单元,而不是许多 cpp/h 文件,其中只有包含修改过的头文件的这些文件将被重新编译。例如,我目前正在处理的应用程序的完整构建需要 7 分钟。如果更改不严重,重新编译大约需要 15 秒。最后,代码的可读性可能会降低。头文件让您快速了解创建类的目的以及如何使用它。如果类是就地编写的,您将不得不不必要地挖掘源代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    相关资源
    最近更新 更多