【问题标题】:C++ How to include class headers without having to compile their cpp files?C++ 如何包含类头而不需要编译它们的 cpp 文件?
【发布时间】:2013-05-10 11:26:59
【问题描述】:

我们可以包含,我们不关心它的cpp文件,但是为什么我们不能对我们自己的类做同样的事情呢?

因此,如果我的项目使用 50 个自定义类,我不仅必须拥有 50 个包含,而且还必须与它们一起编译/链接 50 个 cpp 文件(并使项目树变得混乱)。

问:是否可以像使用标准库一样使用自定义标头?

换句话说,有没有一种洁净的方式,这样我们就不必在项目中添加所有这些 cpp 文件。我只想包含 ClassSnake.hpp,它又知道在哪里可以找到 ClassSnake.cpp,它链接到 ClassVector.hpp,它知道如何找到 ClassVector.cpp ...所有这些都在自动菊花链中,而无需我显式添加那些 cpp 文件在我的项目树中。

编辑:我不太担心重新编译 cpp 文件。我的问题是必须记住哪个类在内部链接到哪个其他类,这样我就可以在项目树中正确包含所有那些隐藏的 cpp 文件......并使树混乱。

【问题讨论】:

  • 基本上:使每个函数inlinetemplate。这应该清空您的 .cpp 文件,此时您可以删除它们。当然不要对 main 这样做。
  • @dionadar,这不是一个好的解决方案。把所有的实现都放在一个头文件中,只是说“使它成为模板”并不能真正解决任何问题。
  • 它实际上会一直重新编译所有代码,因为不再有单独的目标文件。所有模板都将在主文件中生成。
  • @Moo-Juice 为什么不呢?将所有内容都放在标头中的问题是包含在多个编译单元中(并且很少与具有内部链接的元素发生名称冲突)。将所有内容都设为templateinline 可以解决这些问题。甚至全局变量也可以这样处理:创建一个返回静态变量引用的内联函数...
  • @MikeSeymour,是的,但这也意味着这些头文件一直在重新编译,并且 cpp 文件不应该一直被重新编译,除非它们的实现变化。它只是将问题转移到每个其他编译单元,确定吗?

标签: c++ header include


【解决方案1】:

不是真的。

您缺少的是您的编译器工具链已经编译了标头中没有的位 <iostream>

您的编译器(实际上是链接器)只是隐式链接此代码,而无需您指定它。

如果您想稍微清理一下您的项目树,您可以创建其他项目,这些项目是供一个主要项目使用的代码库。

【讨论】:

  • 所以没有办法自动菊花链?在 First.hpp 文件中有一些东西可以寻找它的 First.cpp 和 First.cpp 文件包括 second.hpp 和 third.hpp,它们知道在哪里可以找到它们各自的 cpp 文件......并自动滴下?
  • 这是您的构建系统需要解决的问题。看起来你正在使用 Code::Blocks.. 它应该已经正确处理了。
  • 我编译项目没有问题。问题在于必须在项目树中包含一堆 cpp 文件而造成的混乱。 (并且必须记住哪个类链接到哪个其他类,以便我每次都可以手动找出那些 cpp 文件以包含在内。)
  • 这是 C++ 编程生活中的一个事实。编译器需要编译您将要使用的代码。您可以随时为您的项目创建子文件夹并组织您的代码。
【解决方案2】:

标头(通常)不提供事物(函数、类)的实现,如果您要使用它们,它们必须在某个地方实现。

当您包含自己的标头时,您会包含自己的源代码以提供实现。直截了当。

当您包含标准头文件(例如 iostream)时,实现在您包含的库中(或者是因为编译器只是执行它而隐式地执行,或者通过编译器/链接器选项显式地执行)。

【讨论】:

  • 愿意解释为什么这应该被否决吗?我会很乐意修复或删除,但不加解释的否决并不是特别有用。
  • 可能只是回答这个问题的其他人之一。
  • @mah,有同样的问题,已标记问题。
  • 我没有投反对票,但这并不能回答问题......“有没有办法像使用标准库一样使用自定义标题?” (尽管它确实描述了一些起作用的底层机制)。
【解决方案3】:

作为 Collin 答案的扩展,您始终可以将“共享”代码卸载到共享库,然后在其他项目中引用头文件和 lib 文件。 lib 文件只会在链接器阶段发挥作用,因为所有其他讨厌的 .cpp 文件都已编译。

如果这只是一个没有其他共性的自封闭项目,那么您将不得不接受您必须提供实现的事实:)

【讨论】:

    【解决方案4】:

    首先,如果您使用诸如 make 之类的系统,那么它将识别出 .cpp 文件没有更改,因此编译器不必重新构建目标文件。

    您还可以创建自己的静态/共享库。执行此操作的方法取决于平台。如果你走这条路,那么你所需要的只是头文件和库。

    请谷歌了解如何构建如何为您的特定平台制作库。

    【讨论】:

      【解决方案5】:

      实际上,如果你有一个像样的构建过程,没有改变的 cpp 文件将不会被再次编译。他们只需要被链接。如果您不希望这样,您需要创建自己的库。是可以的,只是涉及的多一点。

      编辑:This question 如果您想创建自己的库,可能会对您有所帮助。

      所以回答已编辑的问题:是的,您可以避免在项目中包含所有这些 cpp 文件,但前提是您不想更改它们。在这种情况下,您可以只创建一个静态或动态库,并且只需要用于链接的符号。在这种情况下,您将创建另一个项目来将所有内容编译到这样的库中。

      【讨论】:

      • 谢谢!这是一个开始。我将研究动态库。感谢您指出方向:-)
      【解决方案6】:

      诸如“iostream”之类的 STL 代码由模板组成,在创建模板实例之前不会实际生成任何代码。

      【讨论】:

      • 实际上,您可以使用显式模板实例化从静态库或共享库中的模板生成代码。编译器可能仍会为您创建的实例生成代码,但通常会在链接时消除。在 C++11 中,您可以将模板声明为 extern,以防止编译器实例化已经存在于其他地方(在库中)的模板。
      • 我的回答在问题的上下文中是正确的。显式实例化不是问题。主要是因为你必须“明确地”使用它。
      • 抱歉,您的回答应该是评论。它没有解决 Op 的实际问题——如何像使用 C++ 标准库一样使用标头。虽然您对如何生成模板代码的描述没有问题,但它并未提供或建议任何类型的解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-14
      • 2010-12-27
      • 2021-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-07
      相关资源
      最近更新 更多