每当我问如何向我的 C++ 项目中添加类或库时,每个人都说我应该创建一个 .h 文件,使用预处理器指令,在其中声明函数原型,并创建一个新的 .cpp 文件来记录其中的函数。最后将 .h 文件包含在我们的 main.cpp 中。但是当我简单地将 cpp/h 添加到我的源文件时,它也可以正常工作。那么,如果我可以将所有代码写入一个文件并将其包含在我的 main.cpp 中,那么创建 .cpp 和 .h 有什么意义呢?
4 回答
这可能会导致两种截然不同的问题。
首先是它会导致构建时间过长。当您将 .cpp 文件分开时,您可以在更改该文件时编译该文件,否则只需将链接器链接到该文件中的函数,而无需每次都重新编译。只要您的项目很小,每次重新编译所有代码都不是什么大问题,但如果项目变得非常大,很快就会变得很麻烦。
第二个问题是相同函数的多个定义。例如假设您在 A.cpp 中定义了一些函数,并且您需要在 B.cpp 和 C.cpp 中使用这些函数。如果你直接在 B.cpp 和 C.cpp 中包含那些函数(而不仅仅是声明)的源代码,然后尝试将 B 和 C 链接在一起,你在 A.cpp 中对所有函数都有多个定义。导致未定义的行为。在大多数情况下,链接器会告诉您函数已被多次定义,但您不能完全依赖它。
- 将代码拆分为文件提供了一个有用的逻辑分组来帮助理解您的程序。
- 在许多情况下,拆分将导致更快的编译。
- 拆分将允许您使用循环依赖项进行操作(尽管应尽可能避免使用它们)。
- 一些编译器将无法处理全部编译为一个的大型项目
main.cpp
。
如果您正在编写小玩具程序,那么将所有内容分解为逻辑上分离的模块可能会比付出更多的努力。/hacks
我在硬盘上保存了几个项目,我在其中进行测试和实验,它们通常只是一个大文件。
但是当你开始研究真实的系统时,事情会变得更加复杂。系统可以是数百万行代码或更多,在数千个不同的子系统中。将所有这些系统彼此分开为大型复杂系统提供了许多好处。
代码是为人类而不是机器编写的。将系统分解成许多小文件就像写一篇有许多段落的文章,每个段落由几个(但不是太多)句子组成。将一篇完整的 1000 字的文章写成一个句子可能是可能的,但读起来会非常痛苦。同样,在数千个组织良好的小文件中找到您要查找的内容比在一个大文件中要容易得多。
分解文件,尤其是头文件,尽可能小但不能更小可以帮助大大加快编译速度。
分解模块有助于分离不同的系统,并确定存在人工耦合的位置。
总而言之,最重要的是它让事情变得更简单,这总是一件好事。
在程序的不同“单元”之间进行清晰、合乎逻辑的划分有助于保持程序整洁。这有助于了解什么去哪里,什么使用什么,以及通常“它们如何组合在一起”。如果您只是将所有内容都包含在一个大代码块中,则很容易“无法正确分离事物”,因此突然之间在 B.cpp 中使用了 A.cpp 中的变量,而不是将变量声明为Ah 中的“extern”,或者更好的是,有一个可以从任何地方访问它的函数,但是实际变量在 B.cpp 中是“受保护的”,所以没有其他人可以使用它。
“将事物分开”的技术称为封装——您只能看到文件头实际暴露的文件的“位”。这样,作为您项目的第二个程序员,我知道我可以在 A.cpp 中更改哪些位(只要它工作相同) - 不在 Ah 中的所有内容都将是“公平的游戏”。Ah 中的内容必须更仔细地处理,因为这意味着 A.cpp 之外的某些东西可能正在使用它,我们需要先查看在何处/如何使用它,然后才能对其进行更改。
这对大型项目有很大的影响。当你有 100 或 200 行代码时,你可以从字面上记住所有的代码行,如果你在 150-160 行改变了一些东西,你可以很容易地记住在 172 和 189 行也使用了相同的变量,所以你那里也需要改变。当您的项目有 2000 行长时,一个人一次了解大部分内容仍然是可以管理的。如果您已经编写了所有 100k 行,您可能仍然可以管理它。当您有 100 万行代码时,其中大部分是 ELSE 编写的,您需要良好的结构来改变事物,而不会导致无法正常工作的混乱。当然,如果你不表现出你一开始就明白应该如何完成,那么你将永远无法参与 5K 线项目。
抱歉,这有点长,但总的想法是:如果你保持干净,整洁,你就有更好的工作方式,最终会导致更好的软件。