需要帮助理解的概念:为什么在头文件中声明一个函数,而在源文件中定义它

Need help in understanding concept: why declare a function in header but define it in source file?

本文关键字:一个 函数 定义 源文件 声明 文件 助理 帮助 为什么      更新时间:2023-10-16

如果这个问题听起来很熟悉,我很抱歉,但我真的很困惑。在现有的问题下,我无法置评。)

我浏览了几个问题,这些问题的答案是:

如果……(在头文件中定义一个函数),然后将头文件包含到两个或多个不同的源文件中,您将拥有同一函数的多个定义。

但是我认为书上教我们总是在header中写definition guard。对于守卫,我们不会有多个定义,对吧?

我试图在书中找到原因,但没有太多帮助:它说原因(为什么函数在头文件中声明,并在源文件中定义)与变量的原因相同(在前一章中)。当我跳到上一章时,没有明确的解释。

为什么在头文件中声明函数,但在源文件中定义它?

调用函数需要声明。它放在头文件中,这样任何想要调用该函数的文件都可以包含头文件并使声明可用。

只能有一个定义,所以只能放在一个源文件中。

对于guard,我们不会有多个定义,对吗?

每个源文件中都有一个包含头文件的定义。该保护可以防止来自同一源文件的多个包含,但不能阻止来自不同源文件的包含。

但是我认为书上教我们总是在头文件中写定义保护。

定义保护防止在一个 C文件中多次包含头文件。它不阻止头文件被包含在多个C文件中。

对于guard,我们不会有多个定义,对吗?

如果你把定义放在一个头文件中,并把这个头文件包含在多个C文件中,那么你最终会得到同一个函数的多个定义。

函数或变量的多个定义将在链接时导致错误,除非该函数或变量是static。在静态函数/变量的情况下,您最终会得到该函数/变量的多个副本,这通常不是期望的结果。

对于guard,我们不会有多个定义,对吗?

不对的。Include守卫确保在编译源文件时,头文件不会被处理两次。但是,当您有多个源文件时,每个文件都是单独编译的,因此include守卫不会阻止多个定义。

这不是一回事,使用定义保护并不能阻止一个实现跨越多个源文件,它可以防止在同一个文件中多次包含相同的声明(这确实会导致编译错误)。

因此,对于直接在头文件中定义的函数,保护是无用的,因为它的实现将包含在多个源文件中,除非编译器选择内联它,否则它将不止一次出现。将实现放在源文件中将使函数在其自己的翻译单元中进行编译,并且对它的任何调用都将相应地解析。

实际上编译器甚至可以内联在源文件中实现的函数,这样就不会发生这种情况。

声明放在标题中。定义在身体里。头文件保护是为了防止在编译时进行多个声明,而在编译单个单元时可能不止一次地包含同一个头文件(通过其他方式)。定义放在程序体中是为了防止在多个对象中包含该定义的多个编译版本在链接时发生冲突。

编辑回复评论,因为我不能格式化评论:

不是可以定义两次相同的东西

相同的东西声明两次不是 OK。

可以预先声明相同的东西两次。

// predeclare:
class thingy;
// declare:
class thingy { int x(); };
// define:
thingy::x() { return 1; }

在编译单个文件时,您放入头文件中的任何内容都可能出现两次,因为头文件经常被其他头文件包含,因此它们被包含多次。头文件保护可以在编译时防止这种情况。

头文件中定义内容的任何内容,如果它们都包含头文件,则可能最终在多个文件的编译中定义,然后在链接时出现两次。头文件保护不能阻止这一点,因此我们避免在头文件中定义内容。

你可以把c++中的#include想象成一个巨大的宏——它的意思是"在你编译它之前,先抓取一个完整的文件,然后把它塞进我的源代码中"。