2

I can't understand something that causes LNK2005 errors that I've encountered. Assume that you have a class A:

File A.h:

    #ifndef A_H
    #define A_H

    class A{
    public:
        static foo(void);
    private:
        static bool m_someVar;
    };

    bool A::m_someVar = false;

    #endif

File A.cpp:

    #include "A.h"

    void A::foo(){
        m_someVar = true;
    }

The code above causes a LNK 2005 however the following code doesn't:

File A.h:

    #ifndef A_H
    #define A_H

    class A{
    public:
        static foo(void);
    private:
        static bool m_someVar;
    };

    #endif

File A.cpp:

    #include "A.h"

    bool A::m_someVar = false;

    void A::foo(){
        m_someVar = true;
    }

Can someone explain why is this happening even though I have include guards? Should I also add #pragma once?

Thanks in advance.

EDIT: here's the compilation error: "error LNK2005: "private: static bool GameManager::m_isGameOver" (?m_isGameOver@GameManager@@0_NA) already defined in Execution.obj"

JohnJohn
  • 325
  • 1
  • 6
  • 17

2 Answers2

3

include guards(both #ifndef and #pragma) doesn't work across compilation units, which is one of the reasons you should never ever ever define anything in a header file, only declare them. Except for templates of course.

A compilation unit is one .cpp-file and all included headers. Each .cpp create an object file containing a middle stage binary representation of the code, this is the compilation stage. These object files are then linked together in the linking stage. Since each .cpp is handled separately in c++ if you have "float foo;" in header.hpp and both a.cpp and b.cpp include header.hpp, how would the compiler know which foo you mean when running the application?

dutt
  • 7,909
  • 11
  • 52
  • 85
  • 3
    _'... never ever ever ever ever ...'_ except for templates. – πάντα ῥεῖ Mar 26 '14 at 15:17
  • Thanks for your answer. I was also "implementing" singleton inside the header file as well but I've reverted back now. Interestingly static variable for singleton was working fine if I've initialized it inside the constructor of the header file. Anyway only putting declarations seems legit. – JohnJohn Mar 26 '14 at 19:00
  • 1
    Singleton is a tricky pattern to get right. In my mind the only valid usage is global initialization, outside of that I find it hides dependencies and hurts more than it helps in the long run. – dutt Mar 27 '14 at 06:51
1

A "static" variable inside a class declaration is actually a declaration for an extern variable that is in the scope of that class. Like every extern variable, it needs a definition in exactly one source file. Otherwise, the linker will complain about it.

You probably include the .h file from more than one source file, so you have more than one definition.

gnasher729
  • 51,477
  • 5
  • 75
  • 98