Funktion bereits in Application.obj definiert



  • Hi,

    Habe wieder Mal so einen Standardfehler. Ich gebe erstmal Pseudocode an, der hoffentlich alles wichtige darstellt. Reicht das nicht, schieb ich hier andren Code rein. Also ich benutze Visual C++ 2008 Express Edition und habe ne Datei header.hpp (ich benutze überall .hpp und hoffe, dass das keinen Unterschied macht):

    #ifndef EXCEPTIONS_
    #define EXCEPTIONS_
    
    // ein paar includes wie iostream oder string
    
    namespace ns
    {
    
       class Exception
       {
       [...]
       };
    
       std::ostream& operator<<(std::ostream& os, Exception& exc)
       { ... }
    
    }
    
    #endif
    

    Diese header.hpp wird mehrfach von verschiedenen Stellen eingebunden. Jeder Header einer erbenenden Klasse bindet sie beispielsweise ein. Somit geschieht jedes Mal ein Include dieses Headers innerhalb eines Headers. Form ist folgende:

    #ifndef BLABLA_
    #define BLABLA_
    
    #include "header.hpp"
    
    namespace ns
    {
      class SpecialException : public Exception
     { [...] };
    }
    
    #endif
    

    Und die einzelnen Exceptions werden dann natürlich in entsprechenden cpp-Dateien eingebunden (und auch in verschiedenen Headern, welche z.B. Implementierungen von statischen Methoden haben, welche ne Exception nutzen).

    Fehlermeldung:

    1>WindowsWindow.obj : error LNK2005: "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl Exceptions::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Exceptions::Exception &)" (??6Exceptions@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV12@AAVException@0@@Z) ist bereits in Application.obj definiert.
    

    Exceptions ist in diesem Fall der Namespace, hätte ich eigentlich auch direkt so benennen können.

    Wo liegt das Problem, Ideen? 😞

    Lg



  • Hmm. Ich würde mal vermuten, dass etwas mit den Includeguards falsch läuft.. Sicher, dass da keine Schreibfehler drinn sind?



  • Also ifndef define und endif stimmen so, da ist kein Fehler drin. Auch die Namen der Defines sind gleich, hab's auch nochmal mit C&P abgesichert. Also bei den Guards sind wohl keine Schreibfehler drin 😞

    Auch #pragma once führt zum selben Ergebnis.



  • drakon schrieb:

    Hmm. Ich würde mal vermuten, dass etwas mit den Includeguards falsch läuft.. Sicher, dass da keine Schreibfehler drinn sind?

    Hi,

    also mal kurz hingeworfen: Includeguards helfen ja nunmal bei templates (wie std::string eines ist) nicht wirklich, wo doch die template-Instanzen tatsächlich in unterschiedlichen Übersetzungeeinheiten gedoppelt sind.
    Ich muss gestehen, dass ich nie so recht verstanden habe, wie Compiler/Linker das denn nun tatsächlich machen, wenn der Standard verlangt, dass diese Situation nicht als "ODR-Verletzung" ansehen darf - es bleibt doch, dass der Linker entscheiden muss, mit welchem Code er den Verweis auflöst.

    Allerdings höre ich zum ersten Mal davon, dass ein MS-Compiler damit Probleme hätte ... "mein" xlC meckert da schon seit Jahren/Versionen und ich kann es ihm nicht verübeln.

    Gruß,

    Simon2.



  • Eisflamme schrieb:

    Also ifndef define und endif stimmen so, da ist kein Fehler drin. Auch die Namen der Defines sind gleich, hab's auch nochmal mit C&P abgesichert. Also bei den Guards sind wohl keine Schreibfehler drin 😞

    Auch #pragma once führt zum selben Ergebnis.

    dann mach es mal besser so:

    inline std::ostream& operator<<(std::ostream& os, Exception& exc)
    {
    /*...*/
    }
    

    bb



  • Okay? Klappt. Cool, vielen Dank. 🙂

    Aber ich dachte eigentlich, dass er das automatisch von selbst inline macht. Verstehe gar nicht so ganz, wieso das jetzt nötig war? Ich hatte inline als Statement kennen gelernt, was man gar nicht mehr selbst nutzen muss, weil der Compiler die Optimierung dafür übernimmt?



  • Das betrifft das Konzept der Inline-Funktionen als solches, nicht das Schlüsselwort. Moderne Compiler können weitgehend selbst entscheiden, ob eine Funktion schlussendlich direkt in den Code eingebunden wird (inline) oder immer noch ein Funktionsaufruf stattfindet.

    Das Schlüsselwort inline führt dazu, dass eine Funktionsdefinition nicht zu Linkerfehlern führt, wenn sie in mehreren Modulen vorkommt. Allerdings wäre es vielleicht klüger, in den Header nur die Deklaration zu schreiben und die Definition in eine einzelne .cpp-Datei auslagern - damit kannst du nämlich die Implementierung ändern, ohne alles neu zu kompilieren, und hast somit kleinere Abhängigkeiten.



  • Nexus schrieb:

    Das Schlüsselwort inline führt dazu, dass eine Funktionsdefinition nicht zu Linkerfehlern führt, wenn sie in mehreren Modulen vorkommt. Allerdings wäre es vielleicht klüger, in den Header nur die Deklaration zu schreiben und die Definition in eine einzelne .cpp-Datei auslagern - damit kannst du nämlich die Implementierung ändern, ohne alles neu zu kompilieren, und hast somit kleinere Abhängigkeiten.

    Würde ich (hier) nicht machen.
    Ich will nicht jedes mal, wenn irgendwo eine Exception verwendet wird, selbst eine Datei dem Projekt hinzufügen müssen...
    Stell dir ma vor, du müsstest immer, wenn du vector/string/list/exception/.. verwenden willst, ne zusätzliche *.cpp hinzufügen...

    bb


Anmelden zum Antworten