5

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
  • 138,810
  • 21
  • 208
  • 365
Rahul Iyer
  • 19,924
  • 21
  • 96
  • 190
  • 2
    Because you defined `operator==` and `operator!=` in the header file! – Brian Bi Sep 07 '16 at 03:45
  • 3
    Commenting before greek dude marks this as exact duplicate of a megathread – M.M Sep 07 '16 at 03:47
  • @Brian Can you explain why that is a problem ? I'm new to C++, but experienced with other programming languages, so don't know these fundamental things... – Rahul Iyer Sep 07 '16 at 03:47
  • @M.M That fixed it ! Can you explain why ? If you create an answer I can mark it as correct.... – Rahul Iyer Sep 07 '16 at 03:48
  • @M.M Is there a canonical answer for multiple definition errors? I can't find one. – Brian Bi Sep 07 '16 at 03:49
  • @M.M In one of the places that I worked, having only one return statement per function was a requirement for "readability" and "code style". :) , which is why I assign to the variable and then return it. – Rahul Iyer Sep 07 '16 at 03:52

1 Answers1

6

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.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • Thanks.. but can you explain why ? I know it works, but why did my non-inline version not work ? I am a beginner to c++ so I don't know many fundamental things about c++, and wouldn't have any either even how to figure out what the error in this case is. – Rahul Iyer Sep 07 '16 at 03:50
  • 1
    @John when you don't mark a function as `inline`, the compiler makes it available for use in other source files. If you have more than one compiled into different source files, the linker assumes they must be different and generates the error when it finds more than one function with the same name. – Mark Ransom Sep 07 '16 at 03:53
  • Ah! Thanks for that answer. I always wondered - but never got around to looking up what inline was for - I heard it was some kind of compiler optimisation but never thought about it. What both you and Mark are saying makes sense... the tragedy of learning other languages before c++ ... :D – Rahul Iyer Sep 07 '16 at 03:54
  • @MarkRansom actually it is available for use in other source files (i.e. has external linkage) whether or not it is marked `inline`. – M.M Sep 07 '16 at 03:56
  • But then shouldn't the header guards prevent it from being a multiple definition error ? – Rahul Iyer Sep 07 '16 at 04:00
  • @John no, each unit is compiled separately. The include guards prevent the same header being processed twice within the same unit. – M.M Sep 07 '16 at 04:03
  • M.M interesting, I had heard that before but never fully thought through the implications. @John you should also make yourself familiar with the [One Definition Rule](http://stackoverflow.com/questions/4193639/inline-function-linkage). – Mark Ransom Sep 07 '16 at 04:10
  • @MarkRansom good link - have added it to my answer if that's ok – M.M Sep 07 '16 at 04:11
  • You're quite welcome. If you think it improves your answer then I am happy to have helped. – Mark Ransom Sep 07 '16 at 04:16