包括 .cpp 文件
Posted
技术标签:
【中文标题】包括 .cpp 文件【英文标题】:Including .cpp files 【发布时间】:2013-10-23 16:21:38 【问题描述】:我在here 之类的地方读到过,您必须包含 .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;
foop.h
#ifndef FOOP_H
#define FOOP_H
int foo(int a);
#endif
foop.cpp
int foo(int a)
return ++a;
有效,但如果我将 #include "foop.h"
替换为 #include "foop.cpp"
会出现错误(使用 Dev C++ 4.9.9.2,Windows):
multiple definition of foo(int)
first defined here
这是为什么?
【问题讨论】:
这个例子应该编译得很好。有没有遗漏的细节? 您是否只包含 .cpp?在这种简单的情况下应该允许这样做。包括 .h 和 .cpp 显然乘法定义了函数 【参考方案1】: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
中也存在定义,所以编译器会因为函数重复而“混淆”。
【讨论】:
我想你可以通过使用#pragma once
指令来解决它。
@xorguy foop.c 和 foop.h 是如何相互了解的?我理解您在回答中所说的内容,但我仍然不清楚 main.cpp 如何知道 foo 的定义? main.cpp 包括 foop.h ware 只是声明而不是 foo 的定义。那么 main.cpp 是如何知道 foo 的定义的呢?
@WakanTanka 如果方法正确(即包括头文件),main.cpp
不知道foo.cpp
,因此不会抛出错误。这就是我们使用头文件的原因。在他的回答中,@xorguy 使用了一个示例,其中main.cpp
是#include cpp 文件。在这种情况下,因为在main.cpp
和foo.cpp
中都定义了相同的函数,所以会引发错误。
编译器会很高兴,它是链接器会显示关于重复实现的错误。同时,如果您从链接中排除 foo.cpp - 即使没有#pragma once
,构建也会成功。但是在大型项目中这样做是浪费编译器时间,因为所有代码都会在任何更改时重新编译。【参考方案2】:
不鼓励包含 .cpp 文件的原因有很多,但并非严格禁止。您的示例应该可以正常编译。
问题可能是您正在编译 main.cpp 和 foop.cpp,这意味着 foop.cpp 的两个副本被链接在一起。链接器抱怨重复。
【讨论】:
【参考方案3】:当你说#include "foop.cpp"
时,就好像你复制了foop.cpp
的全部内容并粘贴到main.cpp
中。
因此,当您编译 main.cpp
时,编译器会发出一个 main.obj
,其中包含两个函数的可执行代码:main
和 foo
。
当您编译@987654328@ 本身时,编译器会发出一个foop.obj
,其中包含函数foo
的可执行代码。
当您将它们链接在一起时,编译器会看到函数foo
的两个定义(一个来自main.obj
,另一个来自foop.obj
)并抱怨您有多个定义。
【讨论】:
【参考方案4】:这归结为定义和声明之间的区别。
您可以在不同的翻译单元或同一个翻译单元中多次声明函数和变量。一旦你声明了一个函数或一个变量,你就可以从那时起使用它。 您只能在所有翻译单元中定义一次非静态函数或变量。多次定义非静态项会导致链接器错误。标头通常包含声明; cpp 文件包含定义。如果您多次包含具有定义的文件,则在链接期间会出现重复项。
在您的情况下,一个定义来自foo.cpp
,另一个定义来自main.cpp
,其中包括foo.cpp
。
注意:如果您将foo
更改为static
,则不会出现链接错误。尽管没有错误,但这不是一件好事。
【讨论】:
这几乎就是我一直在寻找的答案。我是 C++ 的新手,例如,如何声明一个类?我应该使用头文件吗?那么如何定义该类以在其他文件中使用?对不起这个问题,无关,但我没有找到合适的帮助:( @TheProHands Take a look at this article.【参考方案5】:你应该只包含头文件。
如果包含头文件,头文件会自动查找.cpp 文件。 --> 这个过程是由 LINKER 完成的。
【讨论】:
这个答案完美地解释了问题中解决的问题。 @pasha 这个答案完全忽略了这个主题的细微差别,同时实际上是错误的。 @enedil 感谢您指出这一点,在 google 上花时间后我现在同意,但请解释一下为什么会这样,也许我可以学到一些其他的东西 @pasha 我曾经读过这个答案,并认为它也是正确的......这是错误的,有点误导。没有这样的“头文件找到.cpp文件”的东西。因为只有 .cpp 文件被编译。头文件只是留在那里并等待一些源文件包含它们。观看此视频以了解更多信息youtube.com/watch?v=3tIqpEmWMLI @Rick 感谢您的链接【参考方案6】:因为One Definition Rule(可能1)。
在 C++ 中,每个非内联对象和函数必须在程序中具有完全 一个 定义。通过#include
ing 定义foo(int)
的文件(CPP 文件),它在foop.cpp 为#include
d 的每个文件和foop.cpp 本身中都定义了(假设foop.cpp 已编译) )。
您可以创建一个函数inline
来覆盖此行为,但我不建议在这里这样做。我从未见过有必要甚至需要#include
CPP 文件的情况。
在某些情况下,需要包含对某事物的定义。当您尝试将模板的定义与模板的声明分开时尤其如此。在这些情况下,我将文件命名为 HPP 而不是 CPP 来表示差异。
1:“(可能)”我在这里说可能是因为您发布的实际代码应该可以正确编译,但考虑到编译器错误,您发布的代码似乎不是一模一样和你正在编译的代码一样。
【讨论】:
【参考方案7】:因为您的程序现在包含 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;
因此多重定义错误
【讨论】:
在main.cpp
中,有没有定义foo(),foo()
是在foop.cpp
文件中定义的。当我们#include<foop.cpp>
时,为什么foop.cpp
中的代码只被粘贴到main.cpp
文件中一次,而foo()
被包含两次?【参考方案8】:
所以我发现,如果您从 Visual Studios 编译,您只需从最终构建(您从中扩展的那个)中排除包含的 .cpp 文件:
Visual Studios:.cpp 文件 > 右键 > 属性 > 配置属性 > 常规 > 从构建中排除 > 是
相信你也可以在命令行编译的时候排除文件。
【讨论】:
【参考方案9】:使用“.h”方法更好 但是如果你真的想包含 .cpp 文件,那么在 foo.cpp 中将 foo(int) 设为静态
【讨论】:
以上是关于包括 .cpp 文件的主要内容,如果未能解决你的问题,请参考以下文章