包括.cpp 文件

我曾经在像 给你这样的地方读到过,你必须包括。H 文件而不是。Cpp 文件,否则将得到一个错误。举个例子

Main.cpp

#include <iostream>
#include "foop.h"


int main(int argc, char *argv[])
{
int x=42;
std::cout << x <<std::endl;
std::cout << foo(x) << std::endl;
return 0;
}

#ifndef FOOP_H
#define FOOP_H
int foo(int a);
#endif

Foop.cpp

int foo(int a){
return ++a;
}

可以工作,但是如果我用 #include "foop.cpp"替换 #include "foop.h",我会得到一个错误(使用 Dev C + + 4.9.9.2,Windows) :

multiple definition of foo(int)
first defined here

为什么会这样?

221391 次浏览

因为您的程序现在包含 foo函数的两个副本,一个在 foo.cpp 中,一个在 main.cpp 中

可以将 # include 看作是指示编译器将该文件的内容复制/粘贴到代码中,因此最终处理的 main.cpp 如下所示

#include <iostream> // actually you'll get the contents of the iostream header here, but I'm not going to include it!
int foo(int a){
return ++a;
}


int main(int argc, char *argv[])
{
int x=42;
std::cout << x <<std::endl;
std::cout << foo(x) << std::endl;
return 0;
}

还有 foo.cpp

int foo(int a){
return ++a;
}

因此出现了多重定义错误

include所做的就是从文件中复制所有的内容(这是 <>""中的参数) ,所以当预处理器完成它的工作时,main.cpp看起来像:

// iostream stuff


int foo(int a){
return ++a;
}


int main(int argc, char *argv[])
{
int x=42;
std::cout << x <<std::endl;
std::cout << foo(x) << std::endl;
return 0;
}

所以 foo 将在 main.cpp中定义,但是在 foop.cpp中也存在定义,因此由于函数复制,编译器“会感到困惑”。

有很多理由不鼓励包含.cpp 文件,但是这并不是严格禁止的。

问题可能是您同时编译 main.cpp 和 foop.cpp,这意味着将两个 foop.cpp 副本链接在一起。链接器正在抱怨复制。

这可以归结为 定义声明之间的区别。

  • 可以在不同的转换单元或同一个转换单元中多次声明函数和变量。一旦声明了一个函数或变量,就可以从那时开始使用它。
  • 在所有的翻译单元中,只能定义一个非静态函数或变量。多次定义非静态项会导致链接器错误。

头部通常包含声明; cpp 文件包含定义。如果多次包含含有定义的文件,则在链接过程中会得到重复的文件。

在您的情况下,一个定义来自 foo.cpp,另一个定义来自 main.cpp,其中包括 foo.cpp

注意: 如果将 foo改为 static,则不会出现链接错误。尽管缺少错误,这是 没有的一件好事。

当你说 #include "foop.cpp"时,就好像你复制了 foop.cpp的全部内容并把它粘贴到了 main.cpp

因此,当编译 main.cpp时,编译器会发出一个 main.obj,其中包含两个函数的可执行代码: mainfoo

编译 foop.cpp时,编译器会发出一个 foop.obj,其中包含函数 foo的可执行代码。

当您将它们链接在一起时,编译器会看到函数 foo的两个定义(一个来自 main.obj,另一个来自 foop.obj) ,并抱怨您有多个定义。

因为 一个定义规则(可能是 1)。

在 C + + 中,每个非内联对象和函数都必须在程序中有精确的 定义。通过对定义 foo(int)的文件(CPP 文件)进行 #include0定义,可以在 foop.CPP 为 #included 的每个文件和 foop.CPP 本身(假设 foop.CPP 已编译)中定义 #include0。

您可以创建一个函数 inline来覆盖这种行为,但我不推荐这样做。我从来没有看到一个情况下,它是必要的,甚至可取的 #include一个 CPP 文件。

在某些情况下,我们希望包含对某些事物的定义。当您尝试将模板的定义与其声明分离时,这一点尤其正确。在这些情况下,我将文件命名为 HPP 而不是 CPP 来表示差异。


1 : “(可能)”我在这里说可能是因为您发布的实际代码应该没有错误地进行编译,但是考虑到编译器错误,您发布的代码似乎不像您正在编译的代码那样是 没错

使用“ . h”方法更好 但是如果您真的想要包含. cpp 文件,那么在 foo.cpp 中使 foo (int) static

您只需包含头文件即可。

如果包含头文件,头文件会自动找到. cpp 文件。 这个过程是由 LINKER 完成的。

所以我发现,如果你是从 Visual Studio 编译,你只需要排除所包含的。Cpp 文件从最终版本(从中进行扩展的版本) :

Visual Studios: . cpp file > 右击 > properties > configuration properties > 一般 > 排除构建 >

我相信您也可以在从命令行编译时排除该文件。

我想澄清一些事情: 包括头文件是不必要的,使链接器理解您想要什么。你只需声明它,它就会被链接好。

Cpp:

#include <iostream.h>
//not including "foop.cpp"!


int foo(int a);


int main(){
std::cout << foo(4) << std::endln;
}
  

Cpp:

int foo(int a){
return a++;
}

我并不鼓励这样做,但是要知道头部并不是你编译代码所必须遵循的某种魔法。