我正在使用Microsoft Visual Studio。 为什么我可以在包含.h文件时访问变量,而不是在以下代码中包含.cpp文件时?
file.h
int i = 10;
file.cpp
int i = 10;
main.cpp包括.h
#include <iostream>
#include "file.h"
int main()
{
std::cout << i << std::endl; // ok: output: 10
return 0;
}
main.cpp包括.cpp
#include <iostream>
#include "file.cpp"
int main()
{
std::cout << i << std::endl; // error: LNK1169, LNK2005
return 0;
}
答案 0 :(得分:2)
这里有两件事情。
当您包含文件时,包含的文件将在编译器开始编译之前粘贴到包含文件中。这意味着main.cpp中有一个完整的file.cpp副本,将被编译。
接下来,Visual Studio想要编译cpp文件。它看到file.cpp是项目的一部分,编译它,并将它与main.cpp的编译输出链接起来以生成可执行程序。
链接器现在必须处理具有自己的int i
的两个文件(可能是link.obj和main.obj)。链接器放弃并打印出多重定义错误消息。它甚至没有试图找出哪一个是正确的,因为只有程序员的意图使一个更正确。您将不得不在未来的C ++标准中等待心灵感应编译器支持来排除那些混乱。在那之前不要这样做。
请注意我之前写的关于被包含文件被复制到包含中的内容。这意味着即使在file.h中定义了int i
,您也没有遇到麻烦。
如果main.cpp和future.cpp都包含file.h,那么您再次拥有两个int i
的文件。 Include guards在这里没有帮助,因为它们只会阻止标题在一个已编译的文件中复制(translation unit)。
解决这个问题的方法是不在头文件中定义标识符,除非你采取措施使它们成为唯一的,或者告诉编译器它们是不行的。强烈不希望没有为替代品定义标识符。
For an identifier that is a variable use the extern
keyword通知编译器i
或任何其他变量存在,但将在其他地方分配。然后,您需要在其他地方准确定义变量。例如:
file.h
extern int i;
file.cpp
int i = 0;
现在main.cpp或任何其他文件可以包含file.h并使用i
。所有这些都使用相同的i
,所以要小心它。要非常非常小心。通常有更好的方法在多个翻译单元之间共享变量,因此请花时间寻找不同的解决方案。调试时间到来时,你很可能会感谢自己。
另一种选择是define the variable as static
file.h
static int i;
使用static
时,包含文件.h的每个文件都有自己的i
,只能在包含文件中看到。链接器不再涉及。这也几乎总是一个坏主意。如果你有必须定义的变量来支持头文件,那么真正所需的头是一个类很好。
For an identifier that is a function, use the inline
keyword.
答案 1 :(得分:1)
.h file
被认为是一个头文件,它只包含函数和类的声明。另一方面,.cpp file
包含定义并具有主要代码。
.cpp files
语句中也不能使用#include
。
有关更多信息,我建议您看一下这个链接:
Why should I not include cpp files and instead use a header?