Vererbung von Singletons



  • Hallihallo, ich hab folgendes Problem:

    wie muss ich ein Singleton-Objekt aufbauen, damit ich nachher davon andere Objekte ableiten kann, also ungefähr so:

    class ObjectManager {
    public:
        ObjectManager* getInstance();
    
    private:
        ObjectManager();
        ~ObjectManager();
        ObjectManager* m_instance;
        vector<Object*> m_objects; // noch irgendwas, das die Klasse verwaltet
    };
    

    und hier z.B. eine abgeleitete Klasse:

    class ParticleManager : public ObjectManager {
    // hier soll alles gleich sein, der vektor soll bloß was anderes speichern, nämlich Instanzen von von "Object" abgeleiten Klassen
    }
    

    gibt es eine Möglichkeit, das zu bewerkstelligen, oder muss ich mir ein anderes Design ausdenken? Der Vorteil an diesem Design wäre jedoch, dass es leicht erweiterbar ist (man muss einfach eine neue klasse ableiten) und dass es dem Open-Closed Principle folgt.

    Vielen Dak schonmal,
    Heinzelotto



  • keine Ahnung was du willst



  • Also ich benutze in meinen Projekten folgende Template-Klasse:

    template<class derived>
    class singleton
    {
    	public:
    		static derived &instance()
    		{
    			static derived d;
    			return d;
    		}
    
    	protected:
    		singleton() {}
    
    	private:
    		singleton( const singleton& );
    };
    

    Die Nutzung funktioniert dann wie folgt:

    class bla: public singleton<bla>
    {
        public:
            void foo();
    }
    
    int main()
    {
        bla::instance().foo();
    }
    


  • ich will es hinkriegen, dass ich eine (vielleicht zusätzlich noch abstrakte) Singleton-Basisklasse habe, von der ich dann weitere Klassen ableiten kann, die dann auch Singleton sind. Ich habe nämlich vor, mehrere Objectmanager zu erstellen, nämlich z.B.: ParticleManager, GravitySourceManager, wobei diese jeweils einen vektor verwalten sollen, der mit Particle-Objekten bzw. mit GravitySource-Objekten gefült wird. Dabei ist anzumerken, dass die Klassen Particle und GravitySource jeweils Subklassen von Object sind (Object wird ja von der singleton-basisklasse verwaltet)

    EDIT: @ The-Kenny:
    Das sieht schonmal gut aus, danke dafür 🙂
    Aber ich muss es auch noch hinkriegen, dass die verschiedenen 'Manager' dann noch zusätzliche funktionen haben können, der ParticleManager z.B. die Methode updateParticles(), die die Partikel updated usw.

    EDIT2: ich sehe gerade, dass mein Problem durhc dein Beispiel ja gelöst werden könnte, ich probiere es mal aus, und melde mich dann nochmal, falls es nicht klappt. Vielen Dank schonmal!



  • Vererbung ist in einem Singleton-Pattern nicht (ohne weiters) möglich ...



  • (D)Evil schrieb:

    Vererbung ist in einem Singleton-Pattern nicht (ohne weiters) möglich ...

    Die GOF behaupten etwas anderes. Unter anderem steht der Code von Th in ähnlicher Form auch in „Design Patterns“.



  • Hmm ich hab damit damals mal Probleme bekommen, da dann die instance-Funktion nicht mehr das gewünschte zurück gab. Kann aber auch daran liegen, dass ich das damals nicht sauber implementiert hatte.



  • Nur der Interresse halber (ist ja schon älter der Thread), aber der Code von TK kann doch kein korrektes Singleton implementieren oder? Denn wenn der Konstruktor von singleton protected ist kann die erbende Klasse den ohne Probleme aufrufen (ansonsten wird das ganze Konstrukt auch nicht funktionieren). Somit habe ich aber nicht das erreicht was ich wollte, dass man von der erbenden Klasse nur eine Instance erzeugen kann. Nur so als Beispiel.

    class test : public singleton<test> {
     //bla bla ......
    }
    
    int main() {
        test temp1;
        test temp2;
     // usw.....
    }
    

    Wenn man den Konstruktor(&Copy) von test jetzt private macht wäre alles korrekt denk ich. Doch dann stellt sich mir die Frage inwiefern das noch elegant ist bzw. einem Arbeit spart.

    Gruß
    Baracke



  • Singleton-Basisklasse habe, von der ich dann weitere Klassen ableiten kann

    Warum willst du ableiten ? richtig, weil du das Singleton nur einmal implementieren willst, und dann durch simple Ableitung oefters verwenden.

    Nun sagen aber Schlaue c++ Designer:

    Erbe nie um wiederzuvewenden, sondern nur um wiederverwendet zu werden

    .
    Zu deutsch: Nur wenn du irgendwo dein Object irgendwo ueber nen Generischen zeiger oder Referenz als Basisklasse ansprechen musst (Schnittstellenprinzip) macht vererbung sinn,
    Ansonsten sind Aggregation und meta programmierung (templates) die bessere wahl, auch wenn sie mehr arbeit bedeuten.

    Und daran sollt man sich halten ....

    Also nimm lieber die Version mit dem template ...

    Ciao ...



  • Baracke_out schrieb:

    Wenn man den Konstruktor(&Copy) von test jetzt private macht wäre alles korrekt denk ich.

    wenn man den konstruktor von test als private deklariert, kann ihn singleton nicht mehr aufrufen (singleton muss das ja aber, um beim ersten mal ein objekt der verwalteten klasse zu instanziieren). Um dieses Problem zu umgehen, habe ich die singleton-klasse als friend der zu verwaltenden klasse deklariert.

    Nur wenn du irgendwo dein Object irgendwo ueber nen Generischen zeiger oder Referenz als Basisklasse ansprechen musst (Schnittstellenprinzip) macht vererbung sinn,

    richtig, das wird in meinem projekt auch zur Genüge gemacht 🙂 ...

    Ansonsten sind Aggregation und meta programmierung (templates) die bessere wahl, auch wenn sie mehr arbeit bedeuten.

    ... aber in diesem fall ist dieser Zweite ansatz schwer umzusetzen, denn die einzige Gemeinsamkeit der klassen sind eine oder zwei (von vielen) funktionen und dass sie Singletons sein sollen. Somit ließe sich das z.B. durch ein template schwer umsetzen und die jetzige Lösung gefällt mir und man kann sofort sehen, dass das objekt ein singleton sein soll.

    Vielen Dank für die vielen Hilfen nochmal,
    Heinzelotto



  • Verstehe ich nicht ganz was das Problem ohne Vererbung sein soll... *grübel*

    struct default_tag{};
    template <class T, class TAG = default_tag> class singleton
    {
    public:
        static T& get_instance()
        {
            static T t;
            return t;
        }
    };
    
    // variante 1:
    class foo { /* ... */ };
    void use_foo()
    {
        singleton<foo>::get_instance().lala();
    }
    
    struct other_foo_tag{};
    void use_other_foo()
    {
        singleton<foo, other_foo_tag>::get_instance().lala();
    }
    
    // variante 2:
    class bar
    {
    public:
        static bar& get_instance()
        {
            return singleton<bar>::get_instance();
        }
    
    private:
        friend class singleton<bar>;
        bar();
        ~bar();
        bar(bar const&);
        bar& operator = (bar const&);
    };
    
    void use_bar()
    {
        bar::get_instance().lala();
    }
    

    Variante 1 ist gut wenn man singletons braucht von Klassen die auch so normal verwendbar sind (files, strings, was auch immer).

    Variante 2 ist gut wenn man eine Klasse braucht die immer "singleton" ist. Wobei ich hier eher einen Namespace + globale Variablen in diesem vorziehe - wozu so tun als wäre etwas eine Klasse was keine ist?


Log in to reply