John John - 3 months ago 7
C++ Question

Why does this not marking an operator overload as inline cause a duplicate definition error?

After creating the following class, compilation fails with many "duplicate symbol" errors. The actual error is not very descriptive :


"duplicate symbol __Zeq.... in :
/Users/myusername/Library/Developer/Xcode/DerivedData/MyProject-asdfasfasdf..../Build/Intermediates/MyProject.build/Debug-iphonesimulator/MyTarget.build/Objects-normal/i386/MyClass.o
"


The above same message appears for many different classes, and appears at the end of compilation, so I don't know what the problem is.

I have checked the following:


  1. Classes that use this, include the Listening.hpp file.

  2. The only definition for this class, is in this file.



What can the problem be ?

#ifndef Listening_hpp
#define Listening_hpp
#include <stdio.h>
#include "EAction.hpp"

class Listening{
private:
int _emitterId;
int _listenerId;
std::string _eventName;
EAction* _actionToTake; //not owned.

protected:

public:

Listening(int emitterId,int listenerId,std::string eventName,EAction* actionToTake) : _emitterId(emitterId),_listenerId(listenerId),_eventName(eventName){
_actionToTake = actionToTake;
}

int getEmitterId()const{
return _emitterId;
}

int getListenerId()const{
return _listenerId;
}

std::string getEventName()const{
return _eventName;
}

EAction* getAction()const{
return _actionToTake;
}
};

bool operator==(const Listening &first,const Listening &other)
{
bool result = false;

if(first.getEmitterId() == other.getEmitterId()){
if(first.getListenerId() == other.getListenerId()){
if(first.getEventName() == other.getEventName()){
if (first.getAction() == other.getAction()) {
result = true;
}
}
}
}

return result;
}

bool operator!=(const Listening &first,const Listening &other)
{
bool result = !(first == other);

return result;
}

#endif /* Listening_hpp */


EAction.hpp

#ifndef EAction_hpp
#define EAction_hpp

#include <stdio.h>
class EAction{
private:
protected:
public:

virtual std::vector<std::size_t> seedList() = 0;
};
#endif /* EAction_hpp */


EDIT: Edited the title - I think this may help people who have a duplicate definition error for other reasons ignore this answer.

M.M M.M
Answer

The free functions in the header file must either be marked inline, or changed to have only declarations in the header:

inline bool operator==(const Listening &first,const Listening &other)
{

and similarly for operator!=.

The original problem is that any unit including this header file will have its object file contain a copy of the operator==. Then the linker sees this and doesn't know which one is meant to be the right one. The inline can be thought of as a linker directive to say "All these functions are the same, just pick one". Link to more detailed answers.

The same problem didn't happen with the class member function bodies because such bodies written inside the class definition are implicitly inline.


Historical note: Originally, inline was primarily an optimization directive. However, nowdays compilers are smart enough to make optimization decisions on their own; so the primary use of inline now is what was once the secondary effect: to avoid multiple definition errors when having a function in a header.


BTW, you can write return bla; , instead of assigning bla to a bool variable and so on.