undefined reference to function



  • Sowas bitte:

    class Image 
    {
    public:
    	virtual ~Image(){};
    };
    
    class Bmp : public Image {};
    
    class ImageLoader
    {
    public:
    	virtual Image* LoadImage() = 0;
    };
    
    class BmpLoader : public ImageLoader
    {
    public:
    	Bmp * LoadImage()
    	{
    		return new Bmp;
    	}
    };
    
    int main(int argc, char* argv[])
    {
    	BmpLoader l;
    	Bmp * img = l.LoadImage();
    
    	delete img;
    	return 0;
    }
    


  • ok hier mal ein Minimalbeispiel - theoretisch kompilierbar (praktisch: Fehler!)

    ich hätt's ja als Datei angehängt, aber ich finde hier keine Option dafür 😉

    #include <iostream>
    
    using std::cout;
    using std::endl;
    
    class Image{
    		protected:
    			long _height;
    			long _width;
    			char* _pixels;
    
    		public:
    			Image(){}
    			Image(unsigned int width, unsigned int height, char* data);
    			virtual ~Image();
    
    			virtual char* getPixels() const = 0;
    			virtual long getHeight() const = 0;
    			virtual long getWidth() const = 0;
    	};
    
    class ImageLoader{
    		public:
    			virtual Image* loadImage(string file)= 0;
    
    			template <typename T>
    			static T transformLittleEndian(int i){
    				return new T();
    			}
    	};
    
    class Bmp : public Image{
    		public:
    			Bmp(unsigned int width, unsigned int height, char* data) :
    				_width(width),
    				_height(height),
    				_pixels(data)
    			{}
    
    			~Bmp(){
    				delete[] _pixels;
    			}
    			char* getPixels() const{
    				return _pixels;
    			}
    			long getHeight() const{
    				return _height;
    			}
    			long getWidth() const{
    				return _width;
    			}
    	};
    
    class BmpLoader : public ImageLoader{
    		public:
    			Bmp* loadImage(string file){
    				cout << "loadimage: " << file << endl;
    				char* data = new char[10];
    				return new Bmp(1, 1,  data);
    			}
    	};
    
    int main(){
    
    	cout << "Launching test..." << endl;
    
    	BmpLoader bmpl;
    	Bmp* img;
    	img = bmpl.loadImage("../testbild.bmp"); //FIXME: crash
    
    	cout << img->getHeight() << endl;
    
    	return 0;
    }
    

    Bin für jede Hilfe dankbar 😉



  • Da war ja noch einiges im Argen. string nicht includet, Bmp per Elementinitialisierer die Member der Basisklasse initialisiert, image mit virtuellem Destruktor OHNE Definition...
    So kompiliert und linkt und läuft es hier:

    #include <iostream>
    #include <string>
    
    using std::cout;
    using std::string;
    using std::endl;
    
    class Image {
        protected:
            long _height;
            long _width;
            char* _pixels;
    
        public:
            Image(){}
            Image(unsigned int width, unsigned int height, char* data)
             : _height(height), _width(width), _pixels(data)
            {}
            virtual ~Image() {};
    
            virtual char* getPixels() const = 0;
            virtual long getHeight() const = 0;
            virtual long getWidth() const = 0;
    };
    
    class ImageLoader {
        public:
            virtual Image* loadImage(string file) const = 0;
    
            template <typename T>
            static T transformLittleEndian(int i){
                return new T();
            }
    };
    
    class Bmp : public Image{
        public:
            Bmp(unsigned int width, unsigned int height, char* data)
             : Image(width, height, data)
            {}
    
            ~Bmp(){
                delete[] _pixels;
            }
            char* getPixels() const{
                return _pixels;
            }
            long getHeight() const{
                return _height;
            }
            long getWidth() const{
                return _width;
            }
    };
    
    class BmpLoader : public ImageLoader{
        public:
            Bmp* loadImage(string file) const {
                cout << "loadimage: " << file << endl;
                char* data = new char[10];
                return new Bmp(1, 1,  data);
            }
    };
    
    int main(){
    
        cout << "Launching test..." << endl;
    
        BmpLoader bmpl;
        Bmp* img;
        img = bmpl.loadImage("../testbild.bmp"); //FIXME: crash
    
        cout << img->getHeight() << endl;
    
        return 0;
    }
    

    Wobei es nicht schön ist, wenn die Basisklasse die Daten hält, die abgeleitete Klasse diese dann aber zerstört.
    Auch könnten die getter direkt nach Image wandern, ist doch doof, wenn die selbe Implementierung in jeder angeleiteten Klasse stehen muss. Ich würde da die Klassenhierarchie und -Aufteilung nochmal überdenken. Reicht es nicht, wenn du eine Klasse "Image" für die Daten hast, und nur verschiedene Loader/Exporter anbietest? Ich sehe jetzt nicht, wie sich ein Bmp gegenüber einem Image im Programm unterscheiden wird, nur die Repräsentation auf der Festplatte ist anders.



  • hey, super, VIELEN DANK!!! 🙂

    Ok, das mit dem string ist wohl beim Kopieren auf der Strecke geblieben...

    Wäre es dann besser, pixels im virtuellen Destruktor der Basisklasse zu zerstören (wird der implizit schon aufgerufen?) und die getters hochzuziehen?

    (dann steht zwar in Bmp nichts mehr drin, aber die Klassenstruktur ist auch für weitere Imagefiles gedacht, die evtl Zusatzattribute haben ;))



  • Noch eine Frage: warum hast du loadImage const gemacht? (und warum funktioniert's nicht auch ohne?)



  • </Exit> schrieb:

    Noch eine Frage: warum hast du loadImage const gemacht? (und warum funktioniert's nicht auch ohne?)

    Weil loadImage das ImageLoader-Objekt nicht verändert, und deshalb als const deklariert werden sollte. Wenn das aber in deinem endgültigen Code NICHT zutreffen sollte (also loadImage auch Member von ImageLoader verändert ooder zwingend notwengie nicht-const-Methoden aufruft), musst du natürlich das const wieder wegmachen, sonst gibt es Compiler-Errors.

    Google mal nach "const correctness".



  • </Exit> schrieb:

    Wäre es dann besser, pixels im virtuellen Destruktor der Basisklasse zu zerstören (wird der implizit schon aufgerufen?) und die getters hochzuziehen?

    (dann steht zwar in Bmp nichts mehr drin, aber die Klassenstruktur ist auch für weitere Imagefiles gedacht, die evtl Zusatzattribute haben ;))

    Wenn es nicht das Normale ist, dass ein Bild Zusatzinfos hat, würde ich nicht auf eine Klassenhierarchie bauen, sondern über " bool Image::hasAdditionalInfo() const " und (z.B.) " std::map<std::string, std::string> Image::getAdditionalInfo() const " regeln. Aber auch sonst - denk nurdaran, dass man in den meisten Fällen mit einem Image-Objekt arbeiten wird, um alle möglichen Subklassen unterstützen zu können (Polymorphie eben), nur um bei den zusätzlichen Infos, die dann am Ende auch noch unterschiedlich heißen sollen, in alle möglichen Richtungen casten zu müssen?
    Vor allem der Umstand, dass du leere (!) Image-Derivate erstellst, nur um deinem selbst gesetzten System treu zu bleiben, ist mehr als fraglich 😉



  • const correctness... da sind wir ja bei einem meiner Lieblingsthemen!

    Das mit dem getAdditionalInfo war auch der erste Versuch (zuerst allerdings mit einem struct), dabei ist dann aber so viel schief gegangen, dass es dann doch eine Vererbungshierarchie wurde 😉

    Jetzt muss ich nur noch das zum laufen bringen... (das Minimalbeispiel läuft, aber das richtige noch nicht)

    Danke aber soweit, jetzt muss ich nur schauen, dass ich wirklich alles ausgebessert bekomme 😉



  • Aaaah, hab endlich den Fehler gefunden der für "undefined reference" verantwortlich war. (Danke trotzdem für die Korrekturen der anderen Fehler!)

    Wen's interessiert: ich habe Eclipse benutzt und es wurden die Header (die im extra Ordner "Header" im Projektverzeichnis sind) nicht (dazugelinkt) EDIT: "eingebunden".

    Abhilfe bietet (unter Eclipse):
    Project -> Properties -> C++ Build -> Settings -> GCC C++ Compiler -> Directories und dann den entsprechenden Ordner adden und
    Project -> Properties -> C++ General -> Paths & Symbols -> Library Paths
    und wieder den Ordner adden 😉



  • </Exit> schrieb:

    ich habe Eclipse benutzt und es wurden die Header (die im extra Ordner "Header" im Projektverzeichnis sind) nicht dazugelinkt.

    Header werden niemals dazugelinkt. Header werden vom Prä-Prozessor eingebunden... Und wenn er die Dateien nicht findet, dann gibt er lauthals eine Warnung/Fehler aus.



  • "undefined reference" ist ja so ein toller Fehler 🙄 - No comment!



  • </Exit> schrieb:

    "undefined reference" ist ja so ein toller Fehler 🙄 - No comment!

    Eigentlich steht da auch "undefined reference to <function>", woraus man genauere Informationen über die Funktion bekommt (sofern man die Fehlermeldung liest).

    Falls du dich nur am "undefined reference" störst, das bezeichnet eben eine Funktion, die im Code referenziert wurde, aber nirgends definiert ist. Also eine ziemlich treffende Beschreibung. Nachdem du den Linkerfehler einmal gehabt hast, ist dir auch unmittelbar klar, worum es geht.


Anmelden zum Antworten