darda
darda

Reputation: 4175

MFC projects cause "multiple definition" linker errors?

Is there something special about how an MFC project handles includes?

Here's the scenario. I like to define my class member functions in the h file, instead of splitting up a class between two files.

In Visual Studio I can create an empty Win32 project and do something like this:

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;
}

This builds just fine.

If I take doubleDef.h into an MFC dialog project, and add #include "doubleDef.h" to the h file of the main dialog, I get LNK2005, saying that func is already defined, making it seem as if the #pragma once is being ignored.

If I instead include doubleDef.h in the main dialog's cpp file, everything is fine. But in the empty Win32 I can include doubleDef.h "multiple times" by doing this:

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;
}

That is, it appears #pragma once works as expected (prevents multiple definitions of doubleDef::func()).

If I turn doubleDef into a template class, then the function definition must be in the h file. Likewise, I can make func inline, either by adding the keyword or implicitly by defining it next to the declaration in the class (as in int func() {return 4;}), and then, again the definition must be in the h file.

According to the documentation, the compiler treats inline as more or less optional, so it seems like if I just want to keep everything in the h file, I can just make everything inline.

What gives?

Upvotes: 4

Views: 417

Answers (3)

Brian from state farm
Brian from state farm

Reputation: 2896

In your simple Win32 project you have one main file that keeps including the same item, basically a no-op. To have multiple of the same include in referenced in the same file does not create a new link.

However with your MFC project you put your header file into mainfrm.h. That file is included in several other files in that project not just the mainfrm.cpp. Essentially creating a new link for each of those other files the main header was included in.

1>MainFrm.obj : error LNK2005: "public: int __thiscall doubleDef::func(void)" (?func@doubleDef@@QAEHXZ) already defined in MfcTest.obj 1>FileView.obj : error LNK2005: "public: int __thiscall doubleDef::func(void)" (?func@doubleDef@@QAEHXZ) already defined in MfcTest.obj 1>ClassView.obj : error LNK2005: "public: int __thiscall doubleDef::func(void)" (?func@doubleDef@@QAEHXZ) already defined in MfcTest.obj 1>OutputWnd.obj : error LNK2005: "public: int __thiscall doubleDef::func(void)" (?func@doubleDef@@QAEHXZ) already defined in MfcTest.obj 1>PropertiesWnd.obj : error LNK2005: "public: int __thiscall doubleDef::func(void)" (?func@doubleDef@@QAEHXZ) already defined in MfcTest.obj

Take a look at that output. You can see each of the other components that thinks it has that object.

To put it another way your original statement of why does it work for one way and not the other is because the complexity of the second example (MFC) actually includes that header all over the place. If you only want it used by the main form then include it in the cpp for it.

Upvotes: 0

Barmak Shemirani
Barmak Shemirani

Reputation: 31609

This was already answered before, here is more detailed explanation:

You cannot define a function more than once, unless it is inline

You cannot declare a function more than once in the same file.

You do need to declare functions and classes multiple times if they are referenced in multiple .cpp files.

#pragma once prevents multiple declarations in the same file. It will not prevent multiple declarations in different files. Multiple declarations is exactly what you want and it is why you are including the files in multiple .cpp files in the first place.

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;
}

In the above example, compile will work fine in multiple .cpp file. The compile routine does not notice multiple definitions. But the linker notices multiple definitions and complains. You have to move the definition to .cpp file or use inline functions.

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;
    }
};

Upvotes: 0

Mark Ransom
Mark Ransom

Reputation: 308402

The #pragma once means the file will only be included once per source file. If you have many source files including it, you will still get a copy in each source file.

By declaring a function inline, you tell the compiler it's OK to have multiple copies - as long as those copies are identical.

The usual way of working is to have the declarations in the header file, and the definitions (implementation) in another source file.

P.S. MFC has nothing to do with your problems.

Upvotes: 6

Related Questions