【问题标题】:Why are function bodies in C/C++ placed in separate source code files instead of headers?为什么 C/C++ 中的函数体放在单独的源代码文件而不是头文件中?
【发布时间】:2018-06-01 09:33:19
【问题描述】:

例如,当我在 C++ 中定义一个类文件时,我总是将函数体与类定义一起放在类头文件 (.h) 中。源代码文件(.cpp)是带有 main() 函数的文件。现在这通常在 pro c++ 程序员中完成,还是他们遵循单独的头文件/源代码文件的约定。

至于 Native C,我确实注意到然后在 GCC 中完成(当然还有 Visual Studio for Windows 中的标头)。

所以这只是一个约定吗?或者这是有原因的?

【问题讨论】:

  • 这只是惯例。
  • @JakeFreeman:约定通常是有原因的。在这种情况下,有绝对非常好的理由
  • 想想吧。如果你把所有东西都放在你的头文件中,这一定意味着你只有一个.cpp 和你的main(),它必须直接、间接地包含整个代码。这可能适用于小程序,但用这种方式编译 Linux 内核祝你好运。
  • 这不是“只是一个约定”。两者都做不同的事情,因此程序员做出适当的选择。请参阅 AnT 的答案。

标签: c++ c header-files


【解决方案1】:

函数体被放入.cpp文件中以实现以下目的:

  1. 让编译器只解析和编译它们一次,而不是强迫它一次又一次地编译它们,在头文件包含的任何地方一次又一次地编译它们。此外,在头实现的情况下,链接器稍后必须检测并消除到达不同目标文件的相同外部链接函数。

    许多现代编译器实现的头文件预编译工具可能会显着减少重复重新编译同一头文件所需的工作量,但它们并不能完全消除问题。

  2. 对模块或库的未来用户隐藏这些函数的实现。实现隐藏技术有助于强制执行某些编程规则,从而减少模块之间的寄生相互依赖性,从而使代码更简洁,编译时间更快。

    我什至会说,即使用户可以访问该库的完整源代码(即没有什么对他们真正“隐藏”),也可以将应该通过头文件可见的内容与不应该看到的内容完全分开可见有利于库的自文档属性(尽管这种分离在仅标头库中也可以实现)。

  3. 使某些函数对外界“不可见”(即内部链接,与您的类方法示例不直接相关)。

  4. 驻留在特定翻译单元中的非内联函数可以进行某些与上下文相关的优化。例如,具有相同尾部的两个不同函数最终可能会“共享”实现这些相同尾部的机器代码。

    在头文件中声明为 inline 的函数在不同的翻译单元中(即在不同的上下文中)编译多次,并且必须在稍后由链接器消除,这使得(如果可能的话)更难以利用这些优化机会。

  5. 我可能错过的其他原因。

【讨论】:

  • 还可以将库与相应的标头一起分发,以便其他人可以在他们的代码中使用它们。
  • 优秀的答案。感谢您解释其背后的实际原因,因为它不仅是惯例,而且是计算效率。
【解决方案2】:

这是一种约定,但也取决于具体需求。例如,如果您正在编写一个希望功能快速(内联)的库,并且您正在设计该库供其他人使用,以使其成为一个简单的 header only 库,那么您可以在头文件中编写所有代码(s) 本身。

另一方面;如果您正在编写一个静态或动态链接的库,并且您正在尝试封装来自用户的内部对象数据。您的函数 - 类成员函数等将以它们应该做的方式编写,以便您的库代码的用户不必担心隐藏该部分的实际实现细节。他们需要知道的关于你的函数和类的只是它们的接口。以这种方式,您将拥有头文件和实现文件。

如果您将函数定义连同它们的声明一起放在头文件中,它们将是内联的并且应该运行得更快,但是您的可执行文件会更大并且每次都必须编译它们。实现细节也会暴露给用户。

如果您将函数定义放在头文件的相关代码文件中,它们将不会内联,您的代码会更小,运行速度可能会慢一些,但您应该只需要编译一次。实现细节对用户隐藏和抽象。

【讨论】:

    【解决方案3】:

    绝对没有理由将函数体放在 'c' 的头文件中。如果头文件包含在多个“c”文件中,这将强制编译器多次定义函数。如果函数是“静态”的,程序中会有多个副本,如果是全局的,链接器会报错。

    类似的推理也适用于 c++。类的“内联”成员和一些模板实现除外。

    如果您在 'cpp' 文件中定义了一个临时类,则可以在其中定义它并在该类中定义函数体。

    【讨论】:

    • 非常简洁的答案。塔恩克斯。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-07
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多