为什么.cpp文件和.h文件之间存在差异?

时间:2017-07-17 21:57:00

标签: c++ c++11 visual-c++

我正在使用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;
}

2 个答案:

答案 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?