2016-09-07 15 views
5

Po utworzeniu następującej klasy kompilacja kończy się niepowodzeniem z wieloma błędami "duplikatu symbolu". Rzeczywisty błąd nie jest bardzo opisowe:Dlaczego nie oznacza to przeciążenia operatora jako wbudowanego, powodującego duplikowanie błędu definicji?

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

powyższy samej wiadomości do wielu różnych zajęć, a pojawia się na końcu zestawienia, więc don nie wiem, na czym polega problem.

Sprawdziłem następujące:

  1. klas, które używają tego dołączyć plik Listening.hpp.
  2. Jedyna definicja dla tej klasy znajduje się w tym pliku.

Co może być problemem?

#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: Pod tytułem - Myślę, że to może pomóc ludziom, którzy mają duplikat Błąd definicji z innych powodów zignorować tę odpowiedź.

+2

Ponieważ zdefiniowałeś 'operator ==' i 'operator! =' W pliku nagłówkowym! – Brian

+3

Komentowanie przed greckim kolesiem oznacza to jako dokładny duplikat megathreada –

+0

@Brian Czy możesz wyjaśnić, dlaczego to jest problem? Jestem nowy w C++, ale doświadczony w innych językach programowania, więc nie znam tych podstawowych rzeczy ... –

Odpowiedz

6

Wolne funkcje w pliku nagłówka musi albo być oznakowane inline lub zmienione mieć tylko deklaracje w nagłówku:

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

i podobnie dla operator!=.

Pierwotny problem polega na tym, że każda jednostka zawierająca ten plik nagłówkowy będzie miała swój plik obiektowy zawierający kopię operator==. Następnie linker widzi to i nie wie, który z nich ma być właściwy. inline można uważać za dyrektywę linkera mówiącą "Wszystkie te funkcje są takie same, po prostu wybierz jedną". Link to more detailed answers.

Ten sam problem nie wystąpił w przypadku ciał funkcji członków klasy, ponieważ takie obiekty zapisane wewnątrz definicji klasy są domyślnie inline.


nota historyczna: Początkowo inline był przede wszystkim dyrektywa optymalizacji. Jednak obecnie kompilatory są na tyle inteligentne, że same podejmują decyzje dotyczące optymalizacji; więc podstawowym zastosowaniem inline jest teraz to, co było kiedyś efektem wtórnym: aby uniknąć błędów wielokrotnej definicji, gdy ma się funkcję w nagłówku.


BTW, można napisać return bla;, zamiast przypisywania bla do zmiennej bool i tak dalej.

+0

Dzięki .. ale możesz wyjaśnić, dlaczego? Wiem, że to działa, ale dlaczego moja nieinwazyjna wersja nie działa? Jestem początkującym w C++, więc nie znam wielu podstawowych rzeczy na temat C++, i nie miałbym żadnego nawet, aby dowiedzieć się, jaki jest błąd w tym przypadku. –

+1

@John, gdy nie zaznaczysz funkcji jako 'inline', kompilator udostępnia ją do użytku w innych plikach źródłowych. Jeśli masz więcej niż jeden skompilowany do różnych plików źródłowych, linker zakłada, że ​​muszą być różne i generuje błąd, gdy znajdzie więcej niż jedną funkcję o tej samej nazwie. –

+0

Ah! Dziękuję za tę odpowiedź. Zawsze się zastanawiałem - ale nigdy nie byłem w pobliżu, by sprawdzić, po co jest wbudowany - słyszałem, że była to optymalizacja kompilatora, ale nigdy o tym nie myślałem. To, co ty i Mark mówicie, ma sens ... tragedia uczenia się innych języków przed C++ ...: D –

Powiązane problemy