【发布时间】:2008-12-02 13:34:44
【问题描述】:
【问题讨论】:
【问题讨论】:
因为它是解决接口与实现问题的快速、肮脏和不优雅的解决方案。
它完全依赖于 C 预处理器,这是抽屉里最笨的工具。
其他解决方案可避免以下问题:
Dviljoen 认为我对此非常努力,他是对的。这几乎是一个40-year old design,来自打孔卡和纸带时代。尽管上面列出了所有潜在的陷阱和问题,但仍有大量使用源/头文件排列的 C/C++ 构建的高质量软件。
【讨论】:
因为这意味着复制可以从源代码中获得的信息。其他语言尽量避免这种代码重复。
在我以前的 C 时代,我也是这样做的。我将所有信息保存在我的 .c 文件中,并在正常构建期间使用一个小工具从它们生成头文件。
【讨论】:
在 C# 的情况下,3.0 specification 状态
因为程序集是 自描述功能单元 包含代码和元数据, 不需要#include C# 中的指令和头文件。这 公共类型和成员包含在 进行了特定的组装 在 C# 程序中只需通过 引用该程序集时 编译程序。
【讨论】:
因为它们是过去的遗留物。
现代语言使用模块和包的概念。
如果您想使用在另一个文件中定义的函数/类,请导入该文件。编译器会计算出符号(即名称),以便您可以使用它们。
C/C++ 方法:手动提取函数/类定义并将它们放在另一个文件中,然后在您想要使用它们的任何地方对这些定义进行文本包含。
【讨论】:
在 C 中,您不能进行前向引用,即。使用尚未在其用途之上定义的功能。标头最初是为此而制作的,作为实现的参考。
我查看了引用问题的接受答案,它是正确的。但是今天,编译速度是一个小问题(也许对于非常大的应用程序除外:清理编译我们拥有的应用程序需要 1/4 小时,至少在 Windows 上)。无论如何,实现的细节都是隐藏的,我们通常只看 API 文档,即。可见界面。
作为轶事,我看到一些 C++ 库在标头中实现了 99%(只有系统请求它们的 .cpp 文件),因此模仿了 Java 风格(当时 C# 还不在这里......)。
【讨论】:
我想说,理想情况下,所有信息都应该放在一个地方,并且有一个模块系统,可以智能地避免重新编译/导入不必要的细节,然后让编译器能够在必要时提取仅接口信息(例如,与图书馆或其他任何东西一起提供)。
【讨论】:
它们在 C# 和 Java 中并不是真正需要的,因为您可以为每个方法指定访问级别(例如公共或私有),此外您还具有 C++ 中没有的反射性。
请注意,对于非 OOP 实践,使用头文件并没有那么糟糕。例如,您可以只在头文件中声明哪些函数应该对客户端公开可用,而通过仅在 .cpp 或 .c 文件中声明它们来隐藏其他函数(因此不可访问)。
【讨论】:
我想说,大多数 OO 语言都从拥有接口中获得了它们所需的全部里程。它提供了头文件的所有灵活性(即 - 将接口与实现分离),同时与使用接口的客户端有更严格的合同(因为它们是由语言/编译器强制执行的)。
【讨论】:
对我来说,C 和 C++ 中的标头是一个重要的时间和生产力下沉。编译...哎呀,忘了修复方法的签名。编译...哎呀,需要在类X中添加方法a。
【讨论】:
为了摆脱头文件,编译器的输出需要包含编译器本身可以理解的代码描述。对于较旧的链接器,这并不容易:它们使用的目标文件不能太聪明。因此,创建代码描述的任务留给了人:头文件。
较新的语言要么完全绕过链接器(解释语言和 VM 语言),要么使用自定义链接器(Turbo Pascal,我也假设为 Delphi)。尽管如此,即使是现在,当您处理链接器(或其年轻的兄弟,动态库加载器)时,您仍需要对库中的内容进行某种描述。
【讨论】:
大多数其他语言不像 C++ 那样迟钝且难以解析和编译,因此分离头文件和实现的“性能优化”并不那么重要。
【讨论】:
在 C/C++ 中,头文件基本上是一种对变量进行分组的方法,否则这些变量需要在使用它们的每个编译单元中声明为外部变量。
然而,这并没有限制 C/C++ 可以处理的问题域的复杂性或多样性。只是编程语言是这样进化的。最终,重要的是链接器以某种方式找出您在程序中使用的变量的所有引用和类型。
与似乎具有本地语言支持以处理对变量和方法的外部引用的新的编程语言相比,C/C++ 执行此操作的方式相当粗糙。
【讨论】: