MFC项目导致“多重定义”链接器错误?

时间:2015-04-07 16:52:38

标签: templates visual-c++ mfc inline linker-errors

MFC项目如何处理包含哪些特殊内容?

这是场景。我喜欢在h文件中定义我的类成员函数,而不是在两个文件之间拆分类。

在Visual Studio中,我可以创建一个空的Win32项目并执行以下操作:

main.cpp中:

#include "doubleDef.h"

int main()
{
    doubleDef t;
    t.func();
    return 0;
}

doubleDef.h:

#pragma once

class doubleDef
{
public:
   int func();
};

int doubleDef::func()
{
    return 4;
}

这构建得很好。

如果我将doubleDef.h带入MFC对话框项目,并将#include "doubleDef.h"添加到主对话框的h文件中,我会收到LNK2005,说func已经定义,使得#pragma once似乎被忽略。

如果我在主对话框的doubleDef.h文件中包含cpp,那么一切都很好。但是在空的Win32中,我可以通过这样做多次包含doubleDef.h

Header.h

#pragma once
#include "doubleDef.h"

那么header1.h

#pragma once
#include "doubleDef.h"

main.cpp中:

#include "Header.h"
#include "Header1.h"

int main()
{
    doubleDef t;
    t.func();
    return 0;
}

也就是说,#pragma once似乎按预期工作(阻止doubleDef::func()的多个定义。)

如果我将doubleDef转换为模板类,则函数定义必须位于h文件中。同样,我可以通过添加关键字来生成func inline,也可以通过在类中的声明旁边定义它来隐式地生成(如在int func() {return 4;}中),然后再次定义< em>必须在h文件中。

根据documentation,编译器将inline视为或多或少是可选的,所以看起来我只想将所有内容保存在h文件中,我可以一切inline

是什么给出了?

3 个答案:

答案 0 :(得分:6)

#pragma once表示该文件仅包含每个源文件一次。如果您有许多源文件,包括它,您仍然会在每个源文件中获得一个副本。

通过声明一个函数inline,您告诉编译器可以拥有多个副本 - 只要这些副本完全相同。

通常的工作方式是在头文件中包含声明,在另一个源文件中包含 definitions (实现)。

P.S。 MFC与你的问题无关。

答案 1 :(得分:0)

之前已经回答过,这里有更详细的解释:

您不能多次定义一个函数,除非它是inline

您不能在同一个文件中多次声明一个函数。

如果在多个.cpp文件中引用函数和类,则需要多次声明它们。

#pragma once可防止同一文件中出现多个声明。它不会阻止不同文件中的多个声明。多个声明正是您想要的,这就是您首先将文件包含在多个.cpp文件中的原因。

class N1 {
public:
    //Declaration 
    //Multiple .cpp files need to know about this class and its members
    int foo();
};

//Definition 
//should be done once. This should go to .cpp file
int N1::foo() {
    return 1;
}

在上面的例子中,compile在多个.cpp文件中可以正常工作。编译例程没有注意到多个定义。但链接器注意到多个定义和抱怨。您必须将定义移动到.cpp文件或使用inline函数。

class N2 
{
public:
    int foo(); 
};

inline int N2::foo() 
{ //valid, even if it is repeated in different files
    return 1;
}

class N3 
{
public:
    int foo() //always valid
    { 
        return 1;
    }
};

答案 2 :(得分:0)

在你的简单Win32项目中,你有一个主文件保持包含相同的项目,基本上是无操作。要在同一文件中引用多个相同的include,则不会创建新链接。

但是,在您的MFC项目中,您将头文件放入mainfrm.h中。该文件包含在该项目中的其他几个文件中,而不仅仅是mainfrm.cpp。基本上为每个其他文件创建一个新的链接,主要标题包含在。

  

1&gt; MainFrm.obj:错误LNK2005:“public:int __thiscall   doubleDef :: func(void)“(?func @ doubleDef @@ QAEHXZ)已定义   MfcTest.obj 1&gt; FileView.obj:错误LNK2005:“public:int __thiscall   doubleDef :: func(void)“(?func @ doubleDef @@ QAEHXZ)已定义   MfcTest.obj 1&gt; ClassView.obj:错误LNK2005:“public:int __thiscall   doubleDef :: func(void)“(?func @ doubleDef @@ QAEHXZ)已定义   MfcTest.obj 1&gt; OutputWnd.obj:错误LNK2005:“public:int __thiscall   doubleDef :: func(void)“(?func @ doubleDef @@ QAEHXZ)已定义   MfcTest.obj 1&gt; PropertiesWnd.obj:错误LNK2005:“public:int   __thiscall doubleDef :: func(void)“(?func @ doubleDef @@ QAEHXZ)已在MfcTest.obj中定义

看看那个输出。您可以看到认为它具有该对象的每个其他组件。

换句话说,你原来的说明为什么它适用于一种方式而不是另一种方式是因为第二个例子(MFC)的复杂性实际上包括了整个地方的那个标题。如果你只想要它由主表单使用,那么将它包含在它的cpp中。