为什么包含.h也会使.cpp源出现呢?

时间:2016-05-05 23:00:39

标签: c++ compilation linker

我是一名经验丰富的程序员,但只有高级语言;我现在正在用C ++做我的第一个非常大的项目。

我有两个课程,ClassAClassB; ClassAClassBs的索引,因此ClassA需要知道ClassB是什么来构建数组,以及{{1}需要知道ClassB是什么,以便在更改内容时更新索引。这两个类都属于他们自己的.h& .cpp文件。

我认为从另一个中包含每个只会导致无限递归,所以我决定在ClassA的开头添加#include "ClassA.cpp"#include "ClassB.cpp";但这样做只会导致编译器警告这些文件中每个类和方法的多个定义。

经过一些实验,我发现包含main.cppClassA.h会产生所需的行为 - 但这没有任何意义,我只包括这些类的原型。当然,真正使它们成为现实的代码永远不会混杂在一起?但确实如此。

我不明白这里发生了什么?为什么包括ClassB.h也会使ClassA.h的实际代码显示出来?为什么包含ClassA导致ClassA.cpp的每个包含都会触发“多个定义”错误,即使它们位于标题屏蔽或其所谓的内容中?

3 个答案:

答案 0 :(得分:6)

缺少的步骤是链接器不会看到ClassA.cppClassB.cpp中的定义,除非这些文件在某些​​时候编译。如果你做了这样的事情:

g++ main.cpp ClassA.cpp ClassB.cpp

然后,ClassA.cppClassB.cppmain.cpp中对定义的所有引用都将得到解决。但是,如果你只做了

g++ main.cpp

然后链接器不知道在ClassA.cppClassB.cpp中找到定义的位置,您可能会收到错误。

如果你正在使用IDE,那么这个细节对你来说是隐藏的:IDE确保只要你将.cpp文件添加到你的“项目”中,它就会在你构建项目时被编译成最终的二进制文件

答案 1 :(得分:1)

这就是C ++的设计方式:

您的类现在不需要其他类的原型,因此您不必包含多个标题。

为什么会这样?好吧,整个应用程序的编译是两个步骤的组合:代码本身的编译然后链接(实际上,在这些之前还有第三步:预处理,但我们可以将这一步视为代码编译的一部分)。

示例函数调用:知道存在具有特定原型类型的函数就足够了(异常:内联函数!)。然后编译器可以生成执行函数调用所需的所有代码,除了函数的实际地址 - 它为它留下了某种占位符。

然后,链接器将编译步骤中生成的所有代码组合到一个单元中。现在知道每个功能的位置,它可以将它们的实际地址填入占位符,无论它们出现在哪里。

答案 2 :(得分:1)

对于每个*.obj文件,C ++代码被编译为.cpp,并且link进程将obj文件编译为可执行文件。

永远不要包含* .cpp,因为它通常会导致重定义问题。

对于每个* .h文件,添加一个宏以避免多个包括:

#ifndef XXX_H
#define XXX_H

//your code goes here

#endif