[c++] Linker Errors

Started by
7 comments, last by mattd 14 years, 5 months ago
I'm working on a project in Codeblocks, using the GNU GCC compiler and it compiles correctly. When it comes to link, I receive the following errors: Linking console executable: bin\Release\EV2.exe obj\Release\main.o:main.cpp:(.text+0x0): multiple definition of `GraphicsManager::GraphicsManager()' obj\Release\ObjectManager.o:ObjectManager.cpp:(.text+0x70): first defined here obj\Release\main.o:main.cpp:(.text+0x280): multiple definition of `GraphicsManager::GraphicsManager()' obj\Release\ObjectManager.o:ObjectManager.cpp:(.text+0x2f0): first defined here obj\Release\main.o:main.cpp:(.text+0x500): multiple definition of `EngineManager::EngineManager()' obj\Release\ObjectManager.o:ObjectManager.cpp:(.text+0x6e0): first defined here obj\Release\main.o:main.cpp:(.text+0xed0): multiple definition of `EngineManager::EngineManager()' obj\Release\ObjectManager.o:ObjectManager.cpp:(.text+0x7d0): first defined here obj\Release\CameraManager.o:CameraManager.cpp:(.text+0x350): multiple definition of `GraphicsManager::GraphicsManager()' obj\Release\ObjectManager.o:ObjectManager.cpp:(.text+0x70): first defined here obj\Release\CameraManager.o:CameraManager.cpp:(.text+0x5d0): multiple definition of `GraphicsManager::GraphicsManager()' obj\Release\ObjectManager.o:ObjectManager.cpp:(.text+0x2f0): first defined here obj\Release\CameraManager.o:CameraManager.cpp:(.text+0x870): multiple definition of `EngineManager::EngineManager()' obj\Release\ObjectManager.o:ObjectManager.cpp:(.text+0x6e0): first defined here obj\Release\CameraManager.o:CameraManager.cpp:(.text+0x960): multiple definition of `EngineManager::EngineManager()' obj\Release\ObjectManager.o:ObjectManager.cpp:(.text+0x7d0): first defined here I have never seen this before. The only thing weird that I see is that when I click build the first time it tells me 0 errors. Only after clicking build twice more does it show me this mess. I can post code if that would help.
Advertisement
The linker is complaining about seeing definitions for GraphicsManager / EngineManager's constructors in different files, namely main.cpp, CameraManager.cpp and ObjectManager.cpp.

Are you defining GraphicsManager / EngineManager's constructors externally from the class definition, but still in their headers? If so, you shouldn't be. Put the definitions in the class definition.

If not, take a look at your code for something else that could be causing this. Defining (instead of just declaring) functions in headers is a good candidate.
Yeah, after messing around I managed to get it working. I did indeed define member functions in my header (doing it with the advice of http://www.parashift.com/c++-faq-lite/inline-functions.html). Here is what I did:

<code>
#ifndef E_ENGINEMANAGER
#define E_ENGINEMANAGER

#include "globals.h"


class EngineManager {
private:
CameraManager _camMan;
GraphicsManager _graMan;
ObjectManager _objMan;
//SoundManager _souMan;
public:
EngineManager();
void show(const std::string& camera);
void update(float time);
void getEvents();
bool pressedDown(sf::Key::Code key);
bool isOpen();
void frame(float time);
};

EngineManager::EngineManager(): _objMan(_graMan) {

}

inline void EngineManager::show(const std::string& camera) {
_graMan.preShow();
_objMan.show(_camMan.getCamera(camera));
_graMan.postShow();
}

inline void EngineManager::getEvents() {
_graMan.getEvents();
}

inline void EngineManager::update(float time) {
_objMan.update(time);
}

inline bool EngineManager::pressedDown(sf::Key::Code key) {
return _graMan.pressedDown(key);
}

inline bool EngineManager::isOpen() {
return _graMan.isOpen();
}

inline void EngineManager::frame(float time) {
update(time);
show("main");
}


#endif
</code>

Was I interpreting what the FAQ said about defining functions in a header incorrectly?
Notice that EngineManager's constructor isn't marked inline.

You could rectify this part by marking it inline, or by moving the constructor into the class definition (definitions like this are implicitly inline), like this:

class EngineManager {private:CameraManager _camMan;GraphicsManager _graMan;ObjectManager _objMan;//SoundManager _souMan;public:EngineManager() : _objMan(_graMan) {}void show(const std::string& camera);void update(float time);void getEvents();bool pressedDown(sf::Key::Code key);bool isOpen();void frame(float time);};// other inline members here


You could also do the same for the externally-defined inlined methods too.

However, as a matter of style, you probably should put that number of members in a separate .cpp source file.
It works now - thank you. I guess I just assumed I could put the constructor's definition in the header file as well. Do you happen to know why this is illegal?
You can, you just need to mark it inlined, either by the inline keyword, or by putting it in the class definition itself. Otherwise it gets defined multiple times (once in each .cpp file that includes it), leading to the linker errors you saw.

(I edited my previous post a little (>_>), check to see if it makes more sense now).
It's a violation of the ODR (One Definition Rule).

C++ allows multiple declarations, but you can only ever have one definition. That's a very rough description of the One Definition Rule.

In case you don't know the difference, these are declarations:
int Foo();class EngineManager{public:    EngineManager();};


These are definitions:
int Foo(){    return 5;}EngineManager::EngineManager(){}


By placing the definition of EngineManager::EngineManager() in a header, it appears multiple times (in different files). Hence, you've violated the ODR and C++ gives you an error.
NextWar: The Quest for Earth available now for Windows Phone 7.
Ok, but then why the heck do inline functions not break this rule?
Because they're an exception. Definitions of the same external inline function across different translation units (.cpp files) are allowed, but they must be the same in each translation unit. So including a header with an external inline function into multiple .cpp files isn't a problem. Check out Wikipedia.

The reason for this is so the compiler actually has the full definition of the inlined function, even in translation units where the class isn't fully defined, so it can actually perform the inlining whenever it wants to. Without it, it wouldn't actually be able to do the inlining in the first place.

This topic is closed to new replies.

Advertisement