[MSVC++] Fehler beim Linken;



  • Hallo, ich bin neu hier.
    Ich heißte Johannes (21 Jahre) und bin z.Z. Fachinformatiker im 3. Lehrjahr.
    Hier in der Arbeit machen wir fast alles mit MFC, aber daheim setzt ich persönlich auf Linux.

    In dem Programm benutze ich keinen Strich MFC!
    Es geht in meinem Code um das Alcatrazproblem. Wenn ihr es nicht kennt ist es auch nicht so schlimm.
    Ein Freund hat mir die Lösung geschrieben und ich wollte einfach mal schnell das in ein Programm fassen.
    Natürlich schön in C++ und verdammt aufwändig. 😃

    Alles Wichtige befindet sich im namespace alcatraz.
    alcatraz::registrator bekommt einen Funktionspointer auf eine Funktion von alcatraz::experiment.
    Dazu musste ich ein paar Sachen static machen (diese habe ich unten im Code fettkursiv).
    Der Code compiliert ohne Fehler, nur beim Linken gibt's dann ein paar nicht aufgelöste Symbole (und ich weiß nicht warum).

    zuerst einmal die main.cpp

    #pragma warning (disable: 4786)
    
    #include "alcatraz.h"
    #include <iostream>
    
    int main()
    {
    	alcatraz::experiment theExperiment(100, std::cout);
    	theExperiment.startExperiment();
    
    	return 0;
    }
    

    alcatraz::registrator ist von alcatraz::insasse abgeleitet.
    alcatraz::experiment hat einen alcatraz::raum und mehrere Inszanzen von alcatraz::insasse.
    Wobei der Registrator einer dieser Insassen ist (z.Z. standardmäßig der Erste).
    Registrator und Insasse werden alle in einem vector<insasse>* gehalten.

    Nur der Registrator kann das Experiment beenden, indem er die ihm übergebene Funktion aufruft.
    Diese setzt "m_bRun" auf false was dann die Endlosschleife unterbricht.

    alcatraz.h
    [cpp]
    #ifndef __ALCATRAZ_H__
    #define __ALCATRAZ_H__

    #include <iostream>
    #include <vector>
    #include <string>
    #include <algorithm>
    using namespace std;

    namespace alcatraz
    {
    typedef void fertigFunc();
    class raum
    {
    public:
    raum();
    ~raum();

    inline bool bLichtAn();
    void schalteLicht(bool bLicht = true);

    protected:
    bool m_bLichtAn;
    };

    class insasse
    {
    public:
    insasse(int nummer, raum*);
    virtual ~insasse();

    inline int getNummer();
    virtual void schalteLicht();

    protected:
    int m_nNummer;
    raum* m_Raum;
    bool m_bWarSchonDrin;
    void setNummer(int nummer);

    };

    class registrator : public insasse
    {
    public:
    registrator(int nummer, raum*, int GesamtAnzahl, fertigFunc* );
    virtual ~registrator();

    virtual void schalteLicht();
    protected:
    int m_nGesamtAnzahl;
    int m_nCount;
    fertigFunc* pdone;
    };

    typedef vector<insasse*> leute;
    typedef vector<int> counter;

    class experiment
    {
    public:
    experiment(int nAnzahl, ostream& out);
    ~experiment();

    void startExperiment();

    protected:
    counter m_counter;

    int m_nAnzahl;
    leute insassen;

    static void stopExperiment();

    static bool m_bRun;
    raum m_Raum;

    ostream& m_out;

    };
    }
    #endif
    [/cpp]

    raum.cpp

    #include "alcatraz.h"
    
    using namespace alcatraz;
    /* alcatraz::raum
    * Implementierung der Klasse alcatraz:raum
    * Diese Klasse beschreibt den Raum und das Licht.
    */
    raum::raum()
    {
    	m_bLichtAn = false;
    }
    
    raum::~raum() {}
    
    inline bool raum::bLichtAn()
    {
    	return m_bLichtAn;
    }
    
    void raum::schalteLicht(bool bLicht)
    {
    	m_bLichtAn = bLicht;
    }
    

    insasse.cpp

    #include "alcatraz.h"
    
    using namespace alcatraz;
    
    /* alcatraz::insasse
    * Implementierung der Klasse alcatraz:insasse
    * Diese Klasse beschreibt einen normalen Gefangenen.
    * Dieser hat eine Nummer und kann im Raum das Licht ANschalten.
    */
    insasse::insasse(int nummer, raum* Raum):
    m_Raum(Raum)
    {
    	m_nNummer = nummer;
    
    	m_bWarSchonDrin = false;
    }
    
    insasse::~insasse() {}
    
    // int getNummer()
    // Nummer des Insassen
    int insasse::getNummer()
    {
    	return m_nNummer;
    }
    
    // void setNummer(int Nummer)
    // Setzt die Nummer des Insassen
    void insasse::setNummer(int nummer) 
    {
    	m_nNummer = nummer;
    }
    
    // void schalteLicht()
    // Schaltet das Licht ein, wenn es im Raum aus war.
    void insasse::schalteLicht() 
    {
    	if(m_bWarSchonDrin)
    		return;
    
    	// Ist im Raum kein Licht an, dann schalte das Licht an!
    	if(!m_Raum->bLichtAn())
    		m_Raum->schalteLicht();
    	else
    		m_bWarSchonDrin = true;
    }
    

    registrator.cpp

    #include "alcatraz.h"
    
    using namespace alcatraz;
    
    /* alcatraz::registrator
    * Implementierung der Klasse alcatraz:registrator
    * Diese Klasse beschreibt den Registrator unter den Gefangenen
    * Dieser hat eine Nummer und kann im Raum das Licht AUSschalten,
    * und ggf. das Experiment beenden.
    */
    registrator::registrator(int nummer, raum* pRaum, int GesamtAnzahl, fertigFunc* done):
    insasse(nummer, pRaum)
    {
    	m_nGesamtAnzahl = GesamtAnzahl - 1;
    	pdone = done;
    }
    
    registrator::~registrator() {}
    
    // void schalteLicht()
    // 
    void registrator::schalteLicht()
    {
    	// Wenn im Raum das Licht brennt ..
    	if(m_Raum->bLichtAn())
    	{
    		// schaltet es der Registrator aus ..
    		m_Raum->schalteLicht(false);
    
    		// und zieht einen Insassen ab.
    		if(--m_nGesamtAnzahl == 0)
    			pdone();
    	}
    }
    

    experiment.cpp

    #include "alcatraz.h"
    
    using namespace alcatraz;
    
    /* alcatraz::experiment
    * Implementierung der Klasse alcatraz:experiment
    * Diese Klasse ist der Container für das Experiment.
    */
    experiment::experiment(int nAnzahl, ostream& out):
    m_out(out)
    {
    	m_nAnzahl = nAnzahl;
    	m_bRun = true;
    	insassen.push_back(new registrator(1, &m_Raum, nAnzahl--, stopExperiment));
    
    	while(nAnzahl > 0)
    		insassen.push_back(new insasse(nAnzahl--, &m_Raum));
    }
    
    experiment::~experiment() {}
    
    // void startExperiment()
    // startet die MainLoop des Experimentes
    // diese Funktion endet wenn das Experiment vorbei ist.
    void experiment::startExperiment()
    {
    	int iCount = 0;
    	int iRand = 0;
    	while(m_bRun)
    	{
    		iCount++;
    		m_out << "Durchgang #" << iCount << ":" << endl; 
    
    		// Zufällig einen auswählen.
    		iRand = rand() % m_nAnzahl;
    
    		m_out << "Nummer " << insassen.at(iRand)->getNummer() << " geht in den Raum. " << endl;
    
    		// Der Insasse betätigt den Lichtschalter.
    		insassen.at(iRand)->schalteLicht();
    
    		if(m_Raum.bLichtAn())
    			m_out << "Das Licht ist AN" << endl;
    		else
    			m_out << "Das Licht ist AUS" << endl;
    
    		// Ich merke mir, wer im Raum war.
    		m_counter.push_back(insassen.at(iRand)->getNummer());
    
    	}
    
    	m_out << "Der Registatrator beendet das Experiment und sagt;" << endl;
    	m_out << "\"Wir waren jetzt ALLe in diesem Raum" << endl;
    
    	sort(m_counter.begin(), m_counter.end());
    	m_out << "Nach " << iCount << "Durchgängen waren all diese im Raum: " << endl;
    	copy(m_counter.begin(), m_counter.end(), ostream_iterator<int>(m_out, "\n"));
    
    }
    
    void experiment::stopExperiment()
    {
    	m_bRun = false;
    }
    

    Die Ausgabe, die ich beim Linken bekomme ist diese hier:

    --------------------Konfiguration: Alcatraz - Win32 Debug--------------------
    Kompilierung läuft...
    experiment.cpp
    insasse.cpp
    main.cpp
    raum.cpp
    registrator.cpp
    Linker-Vorgang läuft...
    experiment.obj : error LNK2001: Nichtaufgeloestes externes Symbol "protected: static bool  alcatraz::experiment::m_bRun" (?m_bRun@experiment@alcatraz@@1_NA)
    experiment.obj : error LNK2001: Nichtaufgeloestes externes Symbol "public: bool __thiscall alcatraz::raum::bLichtAn(void)" (?bLichtAn@raum@alcatraz@@QAE_NXZ)
    insasse.obj : error LNK2001: Nichtaufgeloestes externes Symbol "public: bool __thiscall alcatraz::raum::bLichtAn(void)" (?bLichtAn@raum@alcatraz@@QAE_NXZ)
    registrator.obj : error LNK2001: Nichtaufgeloestes externes Symbol "public: bool __thiscall alcatraz::raum::bLichtAn(void)" (?bLichtAn@raum@alcatraz@@QAE_NXZ)
    experiment.obj : error LNK2001: Nichtaufgeloestes externes Symbol "public: int __thiscall alcatraz::insasse::getNummer(void)" (?getNummer@insasse@alcatraz@@QAEHXZ)
    Debug/Alcatraz.exe : fatal error LNK1120: 3 unaufgeloeste externe Verweise
    Fehler beim Ausführen von link.exe.
    
    Alcatraz.exe - 6 Fehler, 0 Warnung(en)
    

    Ich frage mich woher die vielen Fehler kommen. Als ich die ganzen Implmentationen in einer Datei hatte, bekam ich nur den Fehler mit "m_bRun".

    Ich hoffe ihr könnt mir helfen.
    Sollte ich etwas zu ungenau beschrieben oder erklärt haben, dann fragt bitte nach.
    Designkritik ist natürlich erwünscht.



  • Hi!

    Der erste Fehler liegt an der statischen Variable m_bRun.
    Statische Klassenvariablen müssen ausserhalb der Klasse noch einmal definiert werden. Also am besten schreibst du zu Anfang der experiment.cpp

    bool experiment::m_bRun = false;
    

    Die restlichen Fehler liegen daran, dass einige Memberfunktionen als inline markiert sind. Bei Inline Funktionen muss der Compiler immer sowohl Deklaration als auch Definition (richtige Begriffe? o.O EDIT: Nochmal nachgeschaut: Ja, richtig :))"sehen" können (google einfach mal danach, wenn's dich interessiert). Das kann er bei dir aber nicht, weil du die Definition in ne .cpp Datei ausgelagert hast. Am besten entfernst du alle 'inline'-Schlüsselwörter aus dem Code. Die Entscheidung liegt letztendlich sowieso beim Compiler ob er die Funktionen inlinet oder nicht.

    Dann sollte's eigentlich gehen.



  • Vielen Dank.

    Das mit den statischen Variablen wusste ich noch gar nicht.
    Und das mit inline auch nicht. :D.
    Normalerweise hatte ich die eh immer im .h drinnen.

    Melde nachher meine Erfolge!

    Erfolge
    Erstmal vielen Dank, dass du dich durch meinen Code durchgewuselt hast.
    Nachdem ich deine Ratschläge befolgt habe und auch noch
    <iterato> inkludiert habe (für ostream_iterator) konnte ich es übersetzten.

    Vielen Dank!


Anmelden zum Antworten