class base : public Singleton<base>; class derived : public base ... wie?
-
Also... voraus schonmal entschuldigung das es sich hierbei um Crossposting handelt, da ich auch schon in www.spieleprogrammierer.de/phpBB2/ die Frage gestellt habe, allerdings brauch ich es dringend und das dauert dort zu lange.
#if !defined (RC_SINGLETON_H__INCLUDED) #define RC_SINGLETON_H__INCLUDED #if (_MSC_VER > 1000) #pragma once #endif namespace realcay { template <class T> class RCWINDOW_API Singleton { public: inline static T& instance() { static T inst; return inst; } protected: Singleton(); public: Singleton(const Singleton&); Singleton& operator=(const Singleton&); }; }; #endif // RC_SINGLETON_H__INCLUDEDist mein Singleton. Dieser liegt in einer DLL ...
Jetzt habe ich eine Klasse ... nennen wir sie "base", die unter anderem folgende Funktionen (oder so ähnlich ;)) drin hat:
#include <map> #define AE_RENDER 1 #define AE_USER 11 class base : public realcay::Singleton<base> { typedef void (base::*EventHandler)(const void*); private: std::map<std::size_t, EventHandler> m_Hndls; public: void send_message(std::size_t id, const void* data) { std::map<std::size_t, EventHandler>::iterator it = m_Hndls.find(id); if (it != m_Hndls.end()) (*this.*it->second)(data); } void register_message(std::size_t id, EventHandler hdnl) { m_Hndls[id] = hdnl; } };Soweit ist ja alles selbsterklärend ... oder? Man kann halt ein Event registrieren (register_message), AE_RENDER usw., und wenn man dann base::instance().send_message aufruft, wird gegebenen Falls die Funktion die registriert wurde, aufgerufen.
Nun sieht man ja an der definition von EventHandler, dass es eine von base abgeleitete Klasse sein muss, um eine Memberfunktion derer problemlos in
einen EventHandler casten zu können. Also kommt eine Klasse derived ins Spiel:class derived : public base { public: derived() : m_int(0) { register_message(AE_RENDER, &derived::on_render); } private: void on_render(const void* data) { std::cout << m_int << std::endl; } private: int m_int; };Jetzt hab ich aber ein Problem mit instance(), da diese Funktion ja ein Objekt von base erstellt, ein derived-Objekt wird aber nie erstellt! Gerade das ist aber von nöten.
Nun könnte ich ja bsw. hingehen und aus base ebenfalls eine template-Klasse machen ... geht aber nicht, da ich in der DLL die Klasse base schon nutze und da ist mir der Name von der abgeleiteten Klasse noch nicht bekannt!
Wie könnte man das Problem umgehen? Hat jemand eine Idee?
-
Das geht so wie du es vorhast garnicht. Ist aber auch nicht besonders sinnvoll, denn da du aus base ein singleton gemacht hast, kann es nur ein einziges base-objekt geben, inclusive aller abgeleiteten Klassen. Sprich, du könntest zwar noch eine klasse derived2 von base ableiten, müsstest dann aber überlegen ob du nur ein Objekt von derived oder eins von derived2 haben willst. Was widerum die Klassenhierarchie an sich fragwürdig macht.
Mögliche Lösungen sind:a) du packst alles was du in derived hast gleich in base rein, wenn du eh keine weitere Klasse von base ableien willst.
b) du machst derived zum Singleton an Stelle von base. Stichwort mehrfache Vererbung. Dann kannst du mehrere abgeleitete Singletons und nicht-singletons haben, die das Verhalten von base erben
c) wenn du tatsächlich ein globales Singleton Objekt benötigst, das aber je nach Umgebungsbedingungen verschiedene Ausprägungen haben soll, dann werden diese verschiedenen Ausprägungen ja alle das selbe Interface haben. dann sollte dein Singleton nur das Interface zur Verfügung stellen und alles andere einem Implementierungs-Objekt überlassen, das du ihm zur Laufzeit gibst.
-
Nunja das Problem ist halt, das ich base als Singleton schon innerhalb der DLL benötige, d.h. kann ich es nicht nur als "normale" Klasse anlegen und zum anderen will ich nicht, das man von base ableiten muss aber kann... also das man, wenn man keine extra Funktionen hat, einfach base nutzen kann(man muss ja nicht unbedingt eine message registriert haben!) und wenn doch, das man dann eine abgeleitete Klasse anlegen muss ...
a) Fällt raus, da es unterschiedliche Teilprogramme sind. Die DLL ist nur das Interface ...
b) Fällt raus ... s.o.
c) wie du meine?Nja werd sonnst in dem Singleton einfach nur einen Pointer speichern, den man dann am Anfang initialisieren muss ... d.h.
class base { typedef void (base::*EventHandler)(const void*); private: std::map<std::size_t, EventHandler> m_Hndls; public: void send_message(std::size_t id, const void* data) { std::map<std::size_t, EventHandler>::iterator it = m_Hndls.find(id); if (it != m_Hndls.end()) (*this.*it->second)(data); } void register_message(std::size_t id, EventHandler hdnl) { m_Hndls[id] = hdnl; } public: inline static base* instance(base* ptr = NULL) { static base* inst = ptr; return inst; } };...
int main() { derived inst; derived::instance(&inst); }oder so ähnlich ...
nen besserne Vorschlag?
-
Von einer Singleton-Klasse abzuleiten, fuert den Singleton ad absurdum. Steht doch in jedem Buch...
Ausserdem, wozu du dir die Muehe machst einen operator= zu schreiben fuer einen Singleton, entzieht sich auch meinem Verstaendnis (gilt auch fuer den Copy-Constr.).
-
der sollte eigentlich auch rpivate sein ... hab hier nen tippfehler drin.
Ausserdem, wozu du dir die Muehe machst einen operator= zu schreiben fuer einen Singleton, entzieht sich auch meinem Verstaendnis (gilt auch fuer den Copy-Constr.).
damit man se nciht nutzen kann setz ich se privat ...
-
Ich würd sagen da haberts grundlegend am Design. Oo
-
Wie bereits gesagt, es ist relativ sinnfrei, von einem Singleton ableiten zu wollen. Denn jedes Objekt der abgeleiteten Klassen beinhaltet ja ein Objekt der Basisklasse. Von daher kannst du nur EIN objekt von GENAU EINER der abgeleiteten Klassen erstellen. Wenn du allerdings, wie du im ersten post sschon schreibst, in der DLL schon die Klasse base benutzt, kannst du davon garnicht mehr ableiten, weil jede Instanz einer abgeleiteten Klasse eine Instanz von base enthaelt - was wegen der Singleton-Eigenschaft von base aber nicht geht. Insofern hat david_pb schon recht dass es da irgendwo am deigns hapert.
Was ich mit c) ausdruecken wollte: Wenn du dem Klienten die Moeglichkeit geben willst, gewisse Features zu Base hinzuzufuegen, kannst du in base dafuer eine Schnittstelle anbieten, allerdings ist der KLient dann daruf beschraenkt. Bsp:
class base : public singleton<base> { public: void changeimpl(baseImpl* newimpl) {delete impl; impl = newimpl;} void ichweisswas1() {cout << "ich weiss was 1" << endl;} //schnittstelle fuer klient: void weissnich1() {imol->weissnich1();} void weissnich2() {impl->weissnich2();} private: baseImpl* impl; base() : impl(0) {}; ~base() {delete impl;} }; class baseImpl { virtual void weissnich1() = 0; virtual void weissnich2() = 0; }So kann der Klient mit changeimpl seine eigene Version der Schnittstelle "weissnich" in die base klasse "injizieren", ohne deren Singleton Eigenschaft aufzubrechen
-
Nja wäre so natürlich auch möglich ... hatte an sowas ähnliches auch schon gedacht gehabt ... für den Zweck reicht aber vollkommen die Funktion die ich oben habe ... auch wenn es sich nicht mehr um einen richtigen Singleton handelt ...