/ C ++项目的基本结构(头文件和cpp文件)

时间:2010-10-07 03:43:38

标签: c++ c include project header-files

这是一个脑死亡的新手问题,但这里有:

什么决定了哪些文件包含在C / C ++项目中?

我的理解是编译器从包含main()的文件开始,该文件将包含#include以获取包含#include到其他h文件的各种h文件,依此类推,直到项目中包含所有内容

我的问题:

h文件和同名cpp文件之间有什么关系?我的意思是,当然我理解代码方面他们需要彼此和cpp文件总是(几乎总是?)#include是h文件,但从编译器的角度来看,重要的是他们有相同的名称或者是这只是一个惯例?我可以包含没有相应h文件的额外cpp文件吗?

此外,在构建和链接项目时,它如何知道构建目标文件的cpp / h文件?它只是从cpp文件开始,其中包含“main()”并继续浏览#include,直到它拥有所需的一切并构建所有这些,或者它只构建用户在makefile或make中指定的所有内容IDE项目文件?

最后,当链接器最终出现并链接所有目标代码以生成可执行文件时,是否有特殊的顺序来安排所有内容?

任何帮助,提示,解释都表示赞赏.. 谢谢!

- R的

4 个答案:

答案 0 :(得分:1)

网上的一点点狩猎会得到很多答案。这只是两个:http://www.psgd.org/paul/docs/cstyle/cstyle02.htm

http://www.cs.utexas.edu/~lavender/courses/EE360C/lectures/lecture-02.pdf

第二个非常好。

我还推荐c ++编程语言第3版。关于文件组织有一个很棒的部分。

至于编译器的作用,最好在另一篇文章中解释。简而言之,每个cpp文件都被编译成一个翻译单元(目标代码),然后链接器将所有内容连接到最终的可执行文件中。

答案 1 :(得分:1)

将文件视为分割代码的简便方法,使其更具可重用性和可维护性。

您可以轻松地将整个应用程序放在一个大的鸣笛源文件中,但您可能会发现该文件会变得相当大,导致编译器抱怨它(或者至少花费很长时间来编译它)。

通常,您会将应用程序的一部分(例如通用数据库访问层)放入单独的源文件(例如db.cpp)中,并使用其API创建db.h文件。 db.cpp使用的文件并不多,因为需要调用db.cpp中的函数的所有其他文件使用它。它可以 包含在db.cpp中,但它主要是发布有关db代码的信息。

关于环境如何确定要编译/链接的内容:您倾向于拥有某种类型的项目(makefile,IDE项目文件等),其中列出了您要编译的所有程序(通常不是头文件) )。

环境将编译已被告知生成目标文件的每个源文件 - 此过程的一部分是将包含的头文件合并到每个源文件中,以构建编译或翻译单元 - 此单元基本上是包含头文件的源文件包含在#include所在的位置。

然后,环境将链接所有目标文件以形成可执行文件。请记住,此过程存在变化,例如延迟(动态)链接。有关此内容的说明,请参阅here

答案 2 :(得分:0)

头文件本质上是类的前向声明及其所有成员属性和函数,这基本上使您的类更可重用且更易于访问。将其视为一个没有实现的接口,因此无论谁使用它都不必担心该特定类的源。据我所知,相应的h文件和cpp文件需要具有相同的名称。一个cpp文件不一定总是有一个相应的h文件,你可以把所有的源都放在一个cpp文件中而不需要任何h文件,只要一切都正确实现并且原型正确,一切都应该正常工作。

答案 3 :(得分:0)

您的分析基本上是正确的...所有包含的文件都已扩展到位,并且生成的代码 - 翻译单元 - 被编译到对象,库或应用程序中。

但是,任何非平凡的项目都依赖于其他库中定义的符号(变量,函数),即使只是用于语言提供的malloc(),socket(),file(),write()等等。或操作系统的标准库。即使你不直接调用它们,也需要实现new和iostream之类的东西。

当您自己的项目变大时,您还需要将您的功能划分为不同的对象或库,因为这使得功能更易于重复使用,可独立测试,并且意味着在更改代码后您只能重新编译那些更改失效的对象然后重新链接 - 这比重新编译整个项目中的每一位代码要快得多。

您的C ++编译器从翻译单元创建对象(可能有也可能没有额外的接口和代码来构建库或应用程序) - 这是您和include的cpp文件的连接提到 - 可能将其与现有静态库中的符号或您在编译器命令行中提到的其他对象进行导入和组合。

对于每个独立对象,编译器需要能够告诉新代码如何访问和使用包含的符号;头文件用于此目的,通告可用的对象内容。

实现(cpp)文件应该几乎总是首先包含它们的头文件,因为如果它正在构建的对象内容与使用该对象的代码稍后期望的头文件广告内容之间存在某些差异,编译器将会抱怨。对于某些事情 - 比如类,必须在指定成员函数实现之前看到类声明,并且假定客户端代码需要类声明,因此在标题中,实际上实现也需要包含标题。 (我说cpp应该包含它的头第一个,因为如果头部依赖于它自己不包含的某些内容,编译器会抱怨。否则,如果说cpp包含std :: string header和header使用它,但是其他一些客户端代码尝试包含头而没有包含字符串,那么编译将失败)。

实现文件可能包含其他实现文件,但这不符合上述编译的一般划分,因此会使用于此约定的人感到困惑。