C++ 理解这个概念需要帮助:为什么在头文件中声明函数而在源文件中定义它?

C++ 理解这个概念需要帮助:为什么在头文件中声明函数而在源文件中定义它?,c++,c,C++,C,(如果这个问题听起来很熟悉,我深表歉意,但我真的很困惑。我无法对现有问题发表评论。) 我浏览了几个问题,答案是: 如果…(在header中定义了一个函数),然后将header包含到两个或多个不同的源文件中,那么同一函数将有多个定义 但我认为这本书教会了我们总是在标题中写定义。有了警卫,我们就不会有多个定义了,对吧 我试图在书中找到原因,但没有得到多少帮助:它说原因(为什么函数在头文件中声明,并在源文件中定义)与变量的原因相同(在上一章中)。当我跳到前一章时,没有明确的解释 有了警卫,我们就不会有

(如果这个问题听起来很熟悉,我深表歉意,但我真的很困惑。我无法对现有问题发表评论。)

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

如果…(在header中定义了一个函数),然后将header包含到两个或多个不同的源文件中,那么同一函数将有多个定义

但我认为这本书教会了我们总是在标题中写定义。有了警卫,我们就不会有多个定义了,对吧

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

有了警卫,我们就不会有多个定义了,对吧

不对。Include guards可确保编译源文件时不会对头文件进行两次处理。但是,当您有多个源文件时,每个文件都是单独编译的,所以include-guard不会停止多个定义

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

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

只能有一个定义,因此它只包含在一个源文件中

有了警卫,我们就不会有多个定义了,对吧


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

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

因此,对于直接在头文件中定义的函数,防护是无用的,因为它的实现随后将包含在多个源文件中,除非编译器选择内联它,否则它将多次出现。将实现放置在源文件中将使编译的函数在其自己的翻译单元中,并且我对它的要求将得到相应的解决


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

头中有一个声明。 定义在正文中。 header guard用于在编译时防止多个声明,同时编译可能多次包含同一header的单个单元(通过其他方法),定义进入正文以防止包含它的多个对象中的定义的多个编译版本在链接时发生冲突

编辑以回答评论,因为我无法格式化评论:

对同一事物定义两次是不合适的

// predeclare:
class thingy;

// declare:
class thingy { int x(); };

// define:
thingy::x() { return 1; }
同一件事申报两次是不行的

// predeclare:
class thingy;

// declare:
class thingy { int x(); };

// define:
thingy::x() { return 1; }
同样的事情可以预先声明两次

// predeclare:
class thingy;

// declare:
class thingy { int x(); };

// define:
thingy::x() { return 1; }
在编译单个文件时,放入头中的任何内容都可能出现两次,因为头通常会被其他头包含,因此它们会被多次包含。头保护在编译时防止出现这种情况

如果在头文件中放置的任何定义了某些内容的内容都包含头文件,那么它们很可能最终会在多个文件的编译中定义,然后在链接时出现两次。头文件防护无法防止这种情况,因此我们避免在头文件中定义内容

你可以把C++中的包含在一个巨大的宏中——这意味着“在抓取整个文件之前,把它推到我的源代码中,然后编译它”。 但我认为这本书教会了我们总是在标题中写定义

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

有了警卫,我们就不会有多个定义了,对吧

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


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

有关您的兴趣,请参见和。@DanielDaranas很好的帖子。很高兴看到一些替代方法以及为什么标题是正确的选择。谢谢你的回答。它用清晰的措辞明确地回答了这个问题。只是好奇,类定义在标题中(我今天刚刚学习了类),这是否意味着类定义中包含了多个内容?(这对于函数定义来说是不合适的)谢谢你的回答。似乎我对多个源文件的编译过程有一些错误的想法。现在我有了更好的理解。只是好奇,类定义在标题中(我今天刚刚学习了类),这是否意味着一个类定义中包含了多个内容?(这对于函数定义不合适)@Minteh不,编译器知道如何处理类定义的多个包含。谢谢你的回答。我不知道多个源文件可能被视为多个翻译单元。只是好奇,类定义在标题中(我今天刚刚学习了类),这是否意味着一个类定义有多个包含?(这对于函数定义来说是不合适的)我误读了你的评论…这是一个有趣的观点…类类型在标题中定义,并且,除其他外,将导致vtable存在…我们得到2个vtable吗?这不再是你最初的问题,我不会