std::vector: Cannot instantiate abstract class



  • Hi
    Ich programmiere gerade ein kleines Spiel und wollte dafür einen SpriteManager als Singleton-Klasse erstellen.

    Jedoch habe ich Probleme wenn ich den std::vector instatieren möchte. Das Problem ist, dass er mir sagt, dass ich meine abstrakte Klasse Sprite nicht als Typ für den std::vector angeben kann.

    Hier der Code von SpriteManager:

    #ifndef SPRITE_MANAGER_12
    #define SPRITE_MANAGER_12
    
    #include <iostream>
    #include <vector>
    
    #include "Sprite.h"
    
    using std::vector;
    
    namespace si
    {
    	// Singleton class to manage the creation, deletion and storage of sprites
    	class SpriteManager
    	{
    	private:
    
    		vector<Sprite> sprites; // std::vector to store the sprite references
    
    		// Constructor, copy constructor and the = operator are declared private so no instances
    		// can be created outside the class
    		SpriteManager() {}
    		SpriteManager( const SpriteManager & ) {}
    		SpriteManager & operator=( const SpriteManager & );
    
    	public:
    
    		// Returns a reference to the singleton class
    		static SpriteManager & get_instance()
    		{
    			static SpriteManager instance;
    			return instance;
    		}
    
    	};
    
    }
    
    #endif
    

    Sprite ist einfach eine abstrakte Klasse, die von zwei anderen abstrakten Klasen erbt, um par Schnittstellen zu bilden.

    Kann mir jemand sagen was ich falsch mache und wie ich das anders lösen / umgehen kann?



  • Sprite hat eine abstrakte Funktion, ist also eine abstrakte Klasse. Du kannst also keine Objekte dieser Klasse erstellen.

    Du willst allerdings Objekte dieser Klasse in deinem vector speichern.. Das geht nicht.



  • Du könntest Zeiger auf Sprites speichern. Dann können Zeiger von ableitenden Klassen hochgecastet und dort gespeichert werden.


  • Mod

    Und falls du dich nun fragst, was eine abstrakte Klasse ist: Dein Sprite hat eine Methode die beispielsweise so deklariert wurde:

    class Sprite{
     virtual void foo()=0;
    };
    

    Oder dein Sprite erbt von einer Klasse mit solch einer Methode und stellt selber keine Definition von foo zur Verfügung.



  • Außerdem ist das keine Singleton Klasse was du da hast.

    static SpriteManager & get_instance()
    {
        static SpriteManager instance;
        return instance;
    }
    

    Hier wird immer wieder was neues zurückgegeben.
    Ändere es ab in:

    static SpriteManager* instance;
    static SpriteManager* get_instance()
    {
        if(!instance)
            instance = new SpriteManager;
        return instance;
    }
    


  • FreakY<3Cpp schrieb:

    Außerdem ist das keine Singleton Klasse was du da hast.

    Doch, ein Meyers-Singleton sogar.
    super feines ding solange du kein multithreading hast, aber dort würde auch deine variante nicht funktionieren 😉





  • Janjan schrieb:

    Mal reinwerfen:
    http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx

    ein SpriteManager ist ein Kandidat der OK für einen Singleton ist.



  • Shade Of Mine schrieb:

    FreakY<3Cpp schrieb:

    Außerdem ist das keine Singleton Klasse was du da hast.

    Doch, ein Meyers-Singleton sogar.
    super feines ding solange du kein multithreading hast, aber dort würde auch deine variante nicht funktionieren 😉

    Und wie genau soll das funktionieren?
    Wenn ich folgenden Code habe:

    class Singleton
    {
        private:
            Singleton() { }
        public:
            static Singleton& get()
            {
                static Singleton s;
                return s;
            }
    
            int Number;
    };
    
    int main()
    {
        Singleton s = Singleton::get();
        s.Number = 5;
        Singleton s2 = Singleton::get();
        std::cout << s2.Number;
    }
    

    Sollte auf meiner Konsole doch dann 5 stehen?
    Tut es aber nicht, hab ich irgendwas vergessen?...



  • Vielleicht solltest du das in deinem Beispiel nicht weglassen 😉

    private:
            SpriteManager( const SpriteManager & ) {}
            SpriteManager & operator=( const SpriteManager & );
    


  • FreakY<3Cpp schrieb:

    Tut es aber nicht, hab ich irgendwas vergessen?...

    Dein Beispiel kompiliert erst gar nicht mit einem korrekt implementierten Singleton, weil du eben keinen neuen Instanzen erstellen kannst.
    Der Zugriff geht so:

    std::cout << Singleton::get().Number
    


  • Bei mir kompiliert es ( Code::Blocks ) 😃
    Aber okay, gut zu wissen. Man denkt wohl anders als C# Liebhaber :p



  • FreakY<3Cpp schrieb:

    Bei mir kompiliert es ( Code::Blocks ) 😃

    Nukularfüsiker schrieb:

    Dein Beispiel kompiliert erst gar nicht mit einem korrekt implementierten Singleton

    Jockelx schrieb:

    Vielleicht solltest du das in deinem Beispiel nicht weglassen 😉

    private:
            SpriteManager( const SpriteManager & ) {}
            SpriteManager & operator=( const SpriteManager & );
    


  • FreakY<3Cpp schrieb:

    Bei mir kompiliert es ( Code::Blocks ) 😃

    der korrekte Code ist wie Jockelx angemerkt hat:

    class Singleton
    {
        private:
            Singleton() { }
            Singleton( const Singleton & );
            Singleton & operator=( const Singleton & );
        public:
            static Singleton& get()
            {
                static Singleton s;
                return s;
            }
    
            int Number;
    };
    
    int main()
    {
        Singleton s = Singleton::get();
        s.Number = 5;
        Singleton s2 = Singleton::get();
        std::cout << s2.Number;
    }
    

    Aber okay, gut zu wissen. Man denkt wohl anders als C# Liebhaber :p

    naja, in c# hast du halt klassen konstruktoren, die erleichtern die arbeit natürlich.



  • Ersma Danke für die vielen Antworten 🙂

    Ja, mir ist klar was eine abstrakte Klasse ist. Ich habe sie extra abstrakt gemacht.

    Ich weiss nur von Java her, dasss ich so etwas schreiben könnte:

    List<Sprite> sprites;
    

    Da dachte ich, dass dies auch in C++ der Fall ist. Klar ist mir, dass ich anschliessend natürlich nur Referenzen der Unterklassen im vector speichern kann. Aber ich dachte durch die Polymorphie wäre dies möglich.

    Ich verstehe nun leider immer noch nicht wie ich das konkret machen kann, dass ich nachher in dem vector alle Referenzen auf Objekte der Unterklassen von Sprite darin speichern kann. Welchen Typ muss ich da angeben? Oder bin ich mal wieder auf dem Holzweg weil ich mühe habe von Java nach C++ umzudenken? ^^



  • icarus2 schrieb:

    Ich verstehe nun leider immer noch nicht wie ich das konkret machen kann, dass ich nachher in dem vector alle Referenzen auf Objekte der Unterklassen von Sprite darin speichern kann. Welchen Typ muss ich da angeben? Oder bin ich mal wieder auf dem Holzweg weil ich mühe habe von Java nach C++ umzudenken? ^^

    In Java hat man ja nur Zeiger.

    Foo f=new Foo();
    

    in C++ hat man aber einen Unterschied zwischen Zeiger und dem Objekt selber.

    Foo f;
    Foo* p=new Foo();
    

    Deshalb muss man auch bei Containern Zeiger angeben (wie man es in Java ja auch macht):

    vector<Foo*> vec;
    

    Da jedes new auch ein delete erfordert ist es, falls der vector die Elemente selber besitzt, sinnvoll boost::ptr_vector zu verwenden...



  • Ui mist, das hatte ich ja ganz vergessen. Vielen Dank für den Hinweis.

    Ich sollte mir boost mal wirklich etwas genauer ansehen. Ich hatte bisher leider noch keine Zeit.

    Danke dir 😉



  • Bei mir ist gerade noch eine Frage bezüglich der Singletons aufgetaucht.

    Wenn ich eine Membervariable mit new erzeuge, so bräuchte ich ja einen Destructor, in dem das Objekt mit delete gelöscht wird. Ich habe mir dann zuerst gedacht, dass ich wirklich einen Destructor dafür nehmen muss. Doch dann fiel mir auf, dass ein Singleton sowiso während der ganzen Laufzeit des Programms existiert. Also brauch ich dafür gar keinen Destructor und es wäre dann vielleicht auch sinnvoller dieses Objekt gar nicht mit new zu erzeugen. Liege ich da richtig?



  • icarus2 schrieb:

    Wenn ich eine Membervariable mit new erzeuge, so bräuchte ich ja einen Destructor, in dem das Objekt mit delete gelöscht wird. Ich habe mir dann zuerst gedacht, dass ich wirklich einen Destructor dafür nehmen muss. Doch dann fiel mir auf, dass ein Singleton sowiso während der ganzen Laufzeit des Programms existiert. Also brauch ich dafür gar keinen Destructor und es wäre dann vielleicht auch sinnvoller dieses Objekt gar nicht mit new zu erzeugen. Liege ich da richtig?

    Wenn du etwas mit new anlegst, musst du es auch irgendwann mit delete loeschen.

    Deshalb sind singletons ein recht komplexes Thema - da das anlegen und zerstoeren nicht ganz trivial ist.

    Der von dir verwendete Meyers Singleton ist solange du nur nicht von mehreren threads aus auf ihn zugreifst ziemlich gut. also lass ihn fuers erste so wie er ist 🙂

    Leider ist es schwer gute Resourcen zu dem Thema zu finden. Wenn du mehr wissen willst mach aber am besten einen neuen Thread auf - denn der wird sicher ziemlich lang werden...



  • Wegen dem new/delete hat jemand mal eine interessante Idee geäussert. Bei einem Singleton wäre es ja nicht so tragisch mal die Ressource nicht freizugeben, weil das ja höchstens einmal passiert. Man hat da dann allerdings garantierte Lebenszeit des Objektes. Sollte nicht unbedingt gemacht werden, wenn es gemieden werden kann, kann allerdings durchaus einen Verwendungszweck haben.

    Aber so als grundsätzliches Singleton ist das von Meyers bestimmt eine gute Idee.


Anmelden zum Antworten