3

我不熟悉使用头文件等,上学期我们在一个巨大的(可怕的:p)文件中完成了所有工作......

我在做我不应该做的事吗?尝试运行程序会导致以下结果:

1>  LINK : ~~~\CSC 161\Accounting Assignment\Debug\Accounting Assignment.exe not found or not built by the last incremental link; performing full link
1>driver.obj : error LNK2005: "class std::basic_ifstream<char,struct std::char_traits<char> > welcomeFile" (?welcomeFile@@3V?$basic_ifstream@DU?$char_traits@D@std@@@std@@A) already defined in statistics.obj
1>~~~~\CSC 161\Accounting Assignment\Debug\Accounting Assignment.exe : fatal error LNK1169: one or more multiply defined symbols found
1>

统计.h:

#ifndef _STATISTICS_INTERFACE_
#define _STATISTICS_INTERFACE_
...
#include<fstream>

using namespace std;
ifstream  welcomeFile;   //if I comment this out, it compiles

class Stats
{
...blah...
};

void welcome();
void pause();
void printFile(ifstream &inFile);

#endif

统计.cpp:

#include "statistics.h"

...working functions...

void welcome()
{
    system("CLS");
    welcomeFile.open("about.txt");
    printFile(welcomeFile);
    welcomeFile.close();
    pause();
}

这些错误看起来像是试图定义两次,但我认为#ifndef 应该设置它,所以它只定义了尚未定义的东西?这是我声明welcomeFile 的唯一地方...

4

2 回答 2

6

因为你在头文件中定义了对象,违反了一个定义规则

永远不要在头文件中定义对象!

标头保护可防止标头的内容在预处理期间多次包含在同一 翻译单元中。它们不会阻止内容包含在不同的翻译单元中。当您将此头文件包含在不同的翻译单元中时,这些单元中的每一个都将具有此对象的定义。
编译器分别编译每个翻译单元以生成一个单独的目标文件(.o),每个 .o 文件都将具有此目标定义的副本。当链接器在生成时试图链接到对象/符号名称时,.exe它会发现同一个对象/符号的多个定义,从而导致对链接到哪一个的混淆。为了避免这个问题,标准定义了一个规则,称为一个定义规则(ODR),它禁止同一实体的多个定义。
如您所见,在头文件中包含对象定义并将该头文件包含在多个翻译单元中违反了 ODR。

如果要使用全局对象,则需要将其声明为extern并定义在一个且只有一个源文件中。

好读:
错误 LNK2005,已定义?

于 2013-01-25T05:52:37.803 回答
2

您应该将该定义放在 .cpp 文件中。否则,包含此 .h 文件的每个文件都将具有此变量的定义,这最终会在链接期间发生冲突。

ps 放入using namespace std;你的标题,被认为是坏的

于 2013-01-25T05:52:48.033 回答