hmm: LNK2019, wie löse ich diesen Fehler in C++?

Hi Leute,

ich bekomme in Visual Studios folgende Fehlermeldung:

modul_XYZ_vs2015.lib(MT_B_C.obj) : 

error LNK2019: unresolved external symbol

"public: __thiscall MT_A_C::MT_A_C(class std::basic_ostream<char,struct std::char_traits<char> > &)"

(??0MT_A_C@@QAE@AAV?$basic_ostream@DU?$char_traits@D@std@@@std@@@Z)

referenced in function "private: static class MT_TestCaseSpec_I &

__cdecl MT_B_C::CreateNewTest(class std::basic_ostream<char,struct std::char_traits<char> > &)"

(?CreateNewTest@MT_B_C@@CAAAVMT_TestCaseSpec_I@@AAV?$basic_ostream@DU?$char_traits@D@std@@@std@@@Z)

Wenn ich in der Methode MT_B_C::CreateNewTest ein darin vorkommendes "new MT_A_C(logfile)" auskommentiere, lässt es sich kompelieren.

Habt ihr eine Idee wie ich den Fehler löse? Was könnte der Grund des Fehlers sein? Includiere ich eventuell zweimal das gleiche ohne es direkt sehen zu können?

akzeptierte Antworten

  1. Hallo hmm,

    also mehr, als dass er offensichtlich den Konstruktor von MT_A_C nicht findet, kann ich angesichts dessen was Du zeigst auch nicht sagen.

    Da es ein Linker-Fehler ist, kein Compiler-Fehler, fehlt ihm zur Linkzeit ein Objektmodul in dem MT_A_C::MT_A_C mit der genannten Signatur auffindbar ist.

    Das kann viele Gründe haben.

    • MT_A_C.obj fehlt weil beim Compile von MT_A_C.cpp ein Fehler auftrat (wobei, dann sollte er eigentlich nicht linken)
    • Das MT_A_C.h, dass Du beim Compile von MT_B_C.cpp verwendest und die Konstruktorsignatur definiert, passt nicht mehr zum MT_A_C.cpp. Deswegen ist die in MT_A_C.obj implementierte Konstruktorsignatur nicht die, die MT_B_C.obj anfordert.
    • Der Konstruktor ist nicht „public genug“ (ich kenne die Sichtbarkeitsregeln von C++ nicht mehr so genau, ist schon viele Jahre her)

    Und bestimmt gibt's noch mehr

    Rolf

    --
    sumpsi - posui - clusi
    1. danke, der konstruktor frisst ein &ostream.

      A(&ostream file):variable(ostream)

      wenn ich 10 mal neubaue ist i.d.r. 1 mal ohne fehler gebaut.…

      kann ich prüfen ob der fehler am ostream liegt?

      frage 2:

      File A includiert File B und File B includiert File C, in File A und in File B steht im header include ostream

      kann das zu einem linkerfehler führen oder kann ich das include ostream in jeden beliebigen header semmeln?

      frage 3:

      kann ich ausschließen dass der lnk-fehler nicht durch einen fehler in einer der visual studios projektmappen erzeugt wird?

      1. Hallo hmm,

        wie gesagt, mein C++ ist schon lange her. ostream wird meines Wissens durch basic_ostream<char...> implementiert, insofern ist das schon ok. Das ganze Templating-Gedöne der Std-Library zeichnet sich durch eine exquisite Unleserlichkeit aus.

        Mehrfacher Include eines System-Headers sollte unschädlich sein, die prüfen das intern ab. Ohne diese Prüfung würde es Compilerfehler HAGELN, wenn Du doppelt includest.

        Wenn Du 10x compilierst, es nur 1x klappt und Du NICHTS änderst zwischendurch, dann ist das aber schon merkwürdig. Eigentlich sollte Studio keine Race-Conditions aufbauen. Sorry, bin raus.

        Rolf

        --
        sumpsi - posui - clusi
  2. Moin @hmm,

    wie sieht denn der betreffende C++-Code dazu aus?

    Viele Grüße
    Robert

    1. Hier etwas abgespeckt:

      class MT_A_C : public MT_Bla_I
      {
      
      public:
        std::ostream& mLogStream;
        MT_A_C(std::ostream& logStream);
      
      }
      
      MT_A_C::MT_A_C(std::ostream& stream):mLogStream(stream) {}
      
      MT_Bla_I& MT_B_C::CreateNewTes(std:ostream& logfile)
      {
        mCurrentTestPtr = new MT_A_C(logfile);
        return *mCurrentTestPtr;
      }
      

      sieht man hier eventuell schon einen möglichen fehler?

      wenn ich die folgende zeile auskommentiere lässt es sich bauen:

      mCurrentTestPtr = new MT_A_C(logfile);
      
      1. Hallo @hmm,

        ich bin mir nicht sicher, aber das könnte Teil des Problems sein:

          std::ostream& mLogStream;
        
        MT_A_C::MT_A_C(std::ostream& stream):mLogStream(stream) {}
        

        Wenn ich mich richtig erinnere, sind Referenzen auf Streams als Attribute in C++ problematisch. Frag mich nicht, wieso.

        Viele Grüße
        Robert

        1. hm... könnte ich eventuell ein problem mit diesem mysteriösen virtual bekommen?

          1. Moin @hmm,

            … könnte ich eventuell ein problem mit diesem mysteriösen virtual bekommen?

            wo steht das denn in deinem Code? Und was hat diese Frage mit meiner Vermutung zu tun? Das sind zwei verschiedene Dinge.

            Viele Grüße
            Robert

            1. im interface MT_Bla_I stehen die meisten methode von MT_A_C als "virtual" drin. wenn ich jetzt den Konstruktor von von MT_A_C im header ändere zu "MT_A_C(ostream& a):mStreamLog(a){}", dann bekomme ich fehlermeldungen im folgenden format:

              error lnk2019 / 2001: unresolved external symbol "public: virtual void ..." und so eine fehlermeldung bekomme ich dann zu jeder methode.

              ka... kann ich das problem irgendwie umgehen und die variable anders übergeben?

              1. Moin,

                im interface MT_Bla_I stehen die meisten methode von MT_A_C als "virtual" drin.

                Es gibt in C++ keine Interfaces. Was meinst du damit?

                virtual heißt lediglich, dass in der Methodentabelle eines Objekts ein echter Pointer auf diese bestimmte Methode hinterlegt wird. Das macht man z.B. bei Basisklassen, wenn im konkreten Fall dann die Methode der abgeleiteten Klasse aufgerufen werden soll anstelle der (vielleicht generischen) der Basisklasse. Mit

                virtual methode() = 0;
                

                kannst du sogar erzwingen, dass abgeleitete Klassen diese Methode implementieren müssen.

                wenn ich jetzt den Konstruktor von MT_A_C im header ändere zu "MT_A_C(ostream& a):mStreamLog(a){}", dann bekomme ich fehlermeldungen im folgenden format:

                Unabhängig von der Fehlermeldung ist es C++ mehr oder weniger gleich, wie die übergebene Variable heißt.

                MT_A_C(std::ostream& stream):mLogStream(stream) und dein obiges MT_A_C(ostream& a):mStreamLog(a) sind äquivalent – bis auf ein Detail: Im ersten Fall wird das Attribut mLogStream, im zweiten das Attribut mStreamLog initialisiert.

                error lnk2019 / 2001: unresolved external symbol "public: virtual void ..." und so eine fehlermeldung bekomme ich dann zu jeder methode.

                Ohne den konkreten Quellcode zu kennen kann ich leider meine Glaskugel nicht kompilieren.

                ka... kann ich das problem irgendwie umgehen und die variable anders übergeben?

                Wie ich schrieb, sind Referenzen auf Streamobjekte problematisch. Du könntest einmal Pointer ausprobieren.

                Viele Grüße
                Robert

                1. Wie ich schrieb, sind Referenzen auf Streamobjekte problematisch. Du könntest einmal Pointer ausprobieren.

                  damit hat es funktioniert. danke.

                  zur feier des tages esse ich jetzt noch nen muffin... während ich 30 min darauf warte dass ich testen kann ob ich den ganzen mist jetzt sauber im clear case eingecheckt hab