Instanzliste



  • hallo,

    ich möchte gerne eine Liste mit allen Instanzen einer Klasse haben.
    Ich habe eine Klasse BaseObject, die als Parentklasse von Polygon und Circle dient. Dort wird der Body der Funktion area definiert.

    class BaseObject{
    public:
    	static std::list<BaseObject *> instanceList; 
    	BaseObject(){
    		instanceList.insert(instanceList.end(), this);
            }
            float area();
    

    Später erstelle ich ein Polygon und will dann die List durchgehen und die area des Polygons ausgeben:

    std::list<BaseObject*>::iterator i;
    	for (i=BaseObject::instanceList.begin(); i!=BaseObject::instanceList.end(); ++i){
    		printf("AREA:%f\n", (*i)->area());
    	}
    

    Ich bekomme beim Kompilieren aber immer die Fehlermeldungen:

    1>GET.obj : error LNK2019: unresolved external symbol "public: float __thiscall BaseObject::area(void)" (?area@BaseObject@@QAEMXZ) referenced in function "void __cdecl polygonDisplay(void)" (?polygonDisplay@@YAXXZ)
    1>GET.obj : error LNK2001: unresolved external symbol "public: static class std::list<class BaseObject *,class std::allocator<class BaseObject *> > BaseObject::instanceList" (?instanceList@BaseObject@@2V?$list@PAVBaseObject@@V?$allocator@PAVBaseObject@@@std@@@std@@A)
    1>H:\GET\Debug\GET.exe : fatal error LNK1120: 2 unresolved externals
    

    Der erste Fehler verschwindet sobald ich einen leeren Body für area bei BaseObject definiere, da ich aber eher Erfahrung in anderen Programmiersprachen habe bin ich mir nicht sicher ob dann auch wirklich die Funktion der Subklasse ausgeführt wird.
    Den zweiten Fehler verstehe ich nicht. woran liegt der denn?



  • Du willst die Methode 'area' überschreiben in Unterklassen?
    Dann musst du das deiner Basisklasse auch klarmachen.
    Das geht mit dem Schlüsselwort virtual. Willst du deine Basisklasse aber abstrakt machen, also gar keine Implementierung anbieten für 'area', dann schreib

    virtual float area() = 0;
    

    Dann muss die Unterklasse diese Methode überschreiben und implementieren.

    Dein zweites problem ist eine Schwäche von C++ (wie ich finde):
    Du musst deinen statischen Member noch definieren, bis jetzt hast du den vector nur deklariert. Schreib in deine Implementationsdatei noch:

    std::list<BaseObject *> BaseObject::instanceList;
    


  • Vielen Dank für die schnelle Antwort aber jetzt bekomme ich immer einen Access Violation Error.
    Ich habe

    std::list<BaseObject *> BaseObject::instanceList;
    

    ganz unten in den baseobject header geschrieben.
    Ich versuche mal alle wichtigen Sachen zu posten:

    class BaseObject{
    public:
    
    	static std::list<BaseObject *> instanceList; 
    	BaseObject(){
    		instanceList.insert(instanceList.end(), this);
    	}
    
    	virtual float area()=0;
    	virtual float *centroid()=0;
    };
    std::list<BaseObject *> BaseObject::instanceList;
    
    class Polygon : public BaseObject{
    public:
    
    	Polygon(){ //stuff
    	}
    	Polygon(int h, float *p[]): BaseObject(){
    		//stuff
    
    	}
    
    	Polygon(int h, float *p): BaseObject(){
    		//stuff
    	}
    
    	float area(){	
            //stuff
    	}
    

    Und so wird das Polygon initialisiert:

    float mat[4][2] = {{0, 0}, {20, 0}, {20, 20}, {0, 20}};
    	Polygon p(4,&mat[0][0]);
    

    Liegt das überhaupt daran oder ist das richtig und ich habe irgendwo anders einen Fehler?



  • Ich denke eher, dass das an deinen Zeigern und C-Arrays liegt.
    Der restliche Code sieht nicht so aus, als dass er Fehler erzuegen sollte.

    Geh einfach mal mit einem Debugger durch und finde so raus, wo genau der Fehler auftritt.

    Wieso willst du eigentlich rohe zeiger in deiner Liste Speichern?
    Und wieso gibst du Arrays per rohen Zeigern an deine Konstruktoren?



  • Danke.
    Ich habe beim debuggen den Fehler soweit eingrenzen können, dass dieser direkt in der forschleife auftritt:

    // hier ist instanceList noch richtig
    for (std::list<BaseObject*>::iterator i=BaseObject::instanceList.begin(); i!=BaseObject::instanceList.end(); ++i){ // hier nicht mehr.
        //pass
    	}
    

    Ich muss also irgendwas beim aufruf der Schleife falsch machen.
    Aber was?



  • Nein, auch die Schleife ist richtig.

    Wenn dein Compiler C++11 unterstützt kannst mal die Range-Based for Schleife probieren:

    (for(auto x : BaseObject::instanceList)
    {
    }
    

    Letztlich wird hier aber auch nur das gleiche gemacht wie bei deiner Schleife.

    Was noch sein kann ist, dass du auf ein Objekt zugreifst, welches schon gelöscht ist. Der Zeiger ist dann nämlich noch in deiner Liste gespeichert...

    #include <iostream>
    #include <memory>
    #include <string>
    #include <algorithm>
    #include <iterator>
    #include <list>
    
    using namespace std;
    
    class BaseObject
    {
    public:
    	static std::list<BaseObject *> instanceList;
    
    	BaseObject()
    	{
    		instanceList.insert(instanceList.end(), this);
    	}
    	virtual ~BaseObject()
    	{
    	}
    
    	virtual float area() = 0;
    };
    
    std::list<BaseObject *> BaseObject::instanceList;
    
    class Polygon : public BaseObject
    {
    public:
    
        float area()
    	{  
            return 0.0f;
        }
    };
    
    int main()
    {
    	Polygon p[10];
    
    	std::list<BaseObject*>::iterator i;
        for (i = BaseObject::instanceList.begin(); i != BaseObject::instanceList.end(); ++i)
    	{
            printf("AREA:%f\n", (*i)->area());
        }
    
    	system("PAUSE");
    	return 0;
    }
    

    Das hier klappt bei mir in Visual Studio 2012 ohne Probleme...
    Keine Fehler, keine Bugs (bei solch einem Trivialen Beispiel jedenfalls ;))



  • Habe meinen Fehler jetzt auch bemerkt.
    Ich hatte das Polygon in einer Funktion erzeugt und dann zurückgegeben:

    Polygon initPolygon(){
    	float mat[4][2] = {{0, 0}, {20, 0}, {20, 20}, {0, 20}};
    	Polygon p(4,&mat[0][0]);
    	return p;
    }
    

    Dann ist es zerstört worden. Ich hab den Teil jetzt in die main Funktion geschrieben und jetzt funktioniert es.
    Vielen Dank für die Hilfe 🙂



  • Ich möchte dich trotzdem nochmal darauf hinweisen, dass dir diese Liste mit rohen Zeigern sehr schnell zum Verhängnis werden kann.

    Den ersten Fehler hattest du schon mit dem zerstörten Objekt...

    Was du vllt mindestens noch machen solltest, wäre jegliche Konstruktoren und Destruktoren mit der Funktionalität auszustatten, dass sie sich in die Liste ein- und AUStragen. (Stichwort: Die großen 3)

    Besser wären da aber std::shared_ptr.

    Die Gretchenfrage ist nur: Was hast du vor und was willst du bezwecken?

    (Typisches XY-Problem)


Log in to reply