2

I am using forward declaration, and I have already been careful not to have any definition inside header files (only declaration), and also have #pragma once directive before each header file. Yet somehow multiple definition error is still happening. So in GlobalSys.h, I use forward declaration, then i will include this file to any file that needs access to this global variable. In application.h, i initialize this global variable so I have to include EventManager.h or the compiler will complain. Where am I doing wrong?

GlobalSys.h

#pragma once
class EventManager;

namespace GlobalSys {
    EventManager * eventManager;
}

Application.h

#include "GlobalSys.h"
#include "../Event/EventManager.h" 

class Application {

public:
    Application();
};

Application.cpp

#include "Application.h"

Application::Application() {
    GlobalSys::eventManager = new EventManager();
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Harry Kane
  • 163
  • 1
  • 7

2 Answers2

2

and I have already been careful not to have any definition inside header files (only declaration)

No, you defined GlobalSys::eventManager in GlobalSys.h.

Definitions are declarations that fully define the entity introduced by the declaration. Every declaration is a definition, except for the following:

  • Any declaration with an extern storage class specifier or with a language linkage specifier (such as extern "C") without an initializer

You can change it to declaration with using of extern.

GlobalSys.h

#pragma once
class EventManager;

namespace GlobalSys {
    extern EventManager * eventManager; // declaration
}

then define it in another implementation file, e.g.

GlobalSys.cpp

#include "GlobalSys.h"

namespace GlobalSys {
    EventManager * eventManager; // definition
}
Community
  • 1
  • 1
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • thank you for ur answer but I am still confused about why my code is wrong. I thought if u do something like this EventManager * eventManager, it would be just a declaration and not a definition? – Harry Kane Jan 29 '19 at 05:18
  • @HarryKane I added some explanations to the answer. – songyuanyao Jan 29 '19 at 05:24
1

once (and other include guards) won't prevent multiple definitions. once prevents a header from being included twice by a single cpp file (translation unit). If multiple translation units include the same header, they will all have their own copy of everything in that header. That includes defined variables and functions. All these translation units are compiled separately, so any one run of the compiler doesn't know that another run already included the header and produced an object file that has its own copy of the same stuff.

The Linker, however, has to take these multiple translation units and put them together into a single program. And it finds all of the duplication. Rather than try to sort out what the programmer really wants, it gives up and asks the programmer to clarify.

Songyuanyao's answer provides one solution for this problem: Declare the variable with extern instead of defining it in the header, and then define the variable in a single translation unit. This allows multiple translation units to share a single variable. You can do the same with a function definition with the inline keyword.

Sometimes, but not this time, you want every translation unit to have their own variable. In that case

#pragma once
class EventManager;

namespace GlobalSys {
    namespace {
        EventManager * eventManager;
    }
}

The anonymous namespace restricts eventManager's linkage to a single translation unit so each translation unit's eventManager do not conflict.

user4581301
  • 33,082
  • 7
  • 33
  • 54