为什么C / C ++中的函数体放在单独的源代码文件而不是标题中?

时间:2017-12-19 01:06:28

标签: c++ c header-files

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

对于Native C,我注意到在GCC中完成(当然还有Visual Studio for Windows中的头文件)。

这只是一个惯例吗?或者有这个原因吗?

3 个答案:

答案 0 :(得分:17)

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

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

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

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

    我甚至会说,即使用户可以访问库的完整源代码(即没有任何东西真正“隐藏”起来),也可以通过头文件和不应该看到的东西之间的清晰分离。可见是有利于库的自我文档属性(尽管这种分离也可以在仅头文件库中实现)。

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

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

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

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

答案 1 :(得分:4)

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

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

如果将函数定义及其声明放在头文件中,它们将是内联的,并且应该运行得更快,但是可执行文件会更大,并且每次都必须编译它们。实现细节也向用户公开。

如果将函数定义放在标题的相关代码文件中,它们将不是内联的,您的代码会更小,运行速度可能会慢一点,但您只需要编译一次。隐藏实施细节并将其从用户中抽象出来。

答案 2 :(得分:1)

绝对没有理由将函数体放在'c'中的头文件中。如果头文件包含在多个'c'文件中,这将迫使编译器多次定义该函数。如果函数是'static',程序中会有多个副本,如果它是全局的,链接器会抱怨。

类似的推理是针对c ++的。例外的是“内联”成员和一些模板实现。

如果在'cpp'文件中定义一个临时类,那么在那里定义它并在类中定义函数体是完全可以的。