Rückgabetyp einer Funktion mit Templates lösen?
-
der clou an dem prinzip plugins "per basisklasse" ist doch gerade
der, dass niemand wissen muss, welche konkrete klasse sich hinter
der schnittstelle verbirgt.
wenn du sowas machen willst:Plugin p = GetPlugin(index); if ( p is KonkretesPluginA ) ... else if ( p is KonkretesPluginB ) ... usw.
hast du nen designfehler und solltest dir ne andere loesung ueberlegen.
sonst macht das ableiten der plugins von einer basisklasse keinen
sinn.
zeig vielleicht mal einen teil des codes her.
:xmas2:
-
Hmmm ich denke hier liegt nen Missverständnis vor. Es geht nicht darum, die konkrete Klasse des Plugins zurückzugeben, sondern nur die Pluginbasisklasse.
XUnknown XComManager::GetPlugin (int pos) { map<int, XComBase*>::iterator data = plgStack.find(pos); XUnknown ret; memset (&ret, 0, sizeof (XUnknown)); if (data != plgStack.end ()) { XComBase* ptr_tmp = data->second; XComVisitor* visitor = new XComDowncastVisitor (); return ptr_tmp->acceptVisitor (visitor); } return ret; }
Problem an der Sache ist das ich hier ne XUnknow Struktur zurückgebe, inder alle Plugins enthalten sind:
typedef struct XUnknown { XComBase* ptr_base; XComGuiBase* ptr_guibase; XComRenderSpec* ptr_renderbase; XComMesh* ptr_mesh; };
XComGuiBase ist dabei die Basisklasse aller Plugins für das erzeugen eines Fensters (XWin32.dll, XQT.dll, XGLUT.dll, ...) XComRenderSpec die Basisklasse aller Renderplugins (XDirectRender, XGL, ...), XComMesh alle Meshplugins (XMesh3ds.dll, XDXFile.dll, XMeshMd2.dll,...) und XComBase* die Basisklasse von dem jedes Plugin abgeleitet ist (also jeweils die Pluginbasisklasse). Und die Struktur will ich jetzt in den Müll hauen und direkt den richtigen Typ zurückgeben.
-
ROFL. So ein Scheiss.
-
Grundsätzlich zum Plugin-System:
Du übersetzt ein Programm, das Plugins unterstützt. Die verwendet überall einfach die Basisklasse und hat die Fähigkeit Objekte aus DLLs zu erhalten.
Dann gibt es Plugins. Die Werden unabhängig von der Anwednung geschrieben, kennen der Code nicht. Lediglich diese Basisklasse, die auch die Anwendung verwendet müssen Sie kennen und wie die Funktion in der DLL heißt, über die das Programm das Objekt beziehen will.
// die Anwendung: class Basis { ... // die Schnittstelle }; ... Basis * foo = getInstancefromDll(...); // läd eine DLL und ruft die Funktion createInstance () auf
// Ein Plugin: class Basis { // muss ebenfalls bekannt sein ... }; class Derivat : public Basis { ... // Implementation der Schnittstelle }; ... Basis * createInstance () { return new Derivat(); }
Ohne die Anwendung neu zu übersetzen kann ich jetzt tausende neuer Plugins schreiben, alle mit neuen Klassen(Typen). Und alle Werden von der Anwendung verwende, ohne das deren Code die Typen jemals zu gesicht bekommen hätte.
Demzufolge ist es absolut unmöglich, in die Abgeleiteten Typen zu Casten, da sie gar nicht existieren.
Natürlich weiss der Anwender nun, was für nen Pointer er auslesen muss, aber das Problem ist, dass die Funktion selber das nicht weiss.
Acuh wenn ich das in dem Zusammenhang absolut nicht verstehe: Schrib erstmal die Funktion, die einfach einen Zeiger mit dem Basistyp zurückgibt.
Sagen wir sei heißt
Basis * getInstanceImpl(size_t index);
.Dann baustdu einfach ne Funktion:
template<typename T> T * getInstance(size_t index) { T * tmp = dynamic_cast<T *>(getInstanceImpl(index)); assert (tmp != 0); return tmp; }
Der user sagt dann einfach:
DerMirBekannteTyp * foo = getInstance<DerMirBekannteTyp>(meinIndex);
-
geht das denn überhaupt mit templates? Ein template wird doch zur Kompilierzeit aufgelöst oder?
Mein Pluginsystem:
Kurz meine Klassenstruktur:
---------------XComBase----------------------------
| | |
XComGuiBase XComRenderSpec XComMesh
| | |
-------------------- ---------------- -------------
| | | | | | |
XWin32 XGlut XQT XDirectRender XGLRender XMesh3ds XMeshMd2class XComBase { public: virtual XUnknown acceptVisitor (XComVisitor* tmp) = 0; private: protected: };
Ich offe die Grafik wird richtig angezeigt, habe sie gerade mal so aufgebaut. Dort sollte meine Hierachie deutlich werden. XComBase soll abstakte Methoden definieren, die alle Pluginbasen überschreiben müssen. Im Moment ist das nur der acceptVisitor, um auf den richtigen Plugintyp zu casten. Jetzt sieht jedes Plugin für die Fenstererstellung so aus:
class XComGuiBase : public XComBase { public: virtual int xCreate (XGuiPrefences* ptr_render, int menu) = 0; virtual int xMain (XGuiPrefences* ptr_render, XComRenderSpec* ptr_base, RENDERFUNC pfunc) = 0; virtual bool showConsole (bool is_shown) = 0; virtual void InfoBox (char* message, char* title) = 0; virtual void ErrorBox (char* message, char* title) = 0; virtual int addButton (int x, int y, int cx, int cy, int id, char* name) = 0; virtual void setKey (int key, bool state) = 0; virtual bool InitCommonControls (void) = 0; virtual bool CreateTreeview (int x, int y, int cx, int cy, int id) = 0; virtual int AddElementToTreeview (int nLocation, char* elem, bool sorted) = 0; virtual XApplication getApplicationInstance (void) = 0; virtual XWindow getMainApplicationWindow (void)= 0 ; virtual XUnknown acceptVisitor (XComVisitor* tmp) { XUnknown test; memset (&test, 0, sizeof (XUnknown)); test.ptr_guibase = tmp->downcast(this); return test; } private: protected: };
Es werden also für die Pluginart benötigte abstrakte Methoden definiert (es sollte jedem klar sein, dass es nicht sinnvoll ist alle von XComBase abzuleiten, da ein Renderplugin mit sicherheit andere Methoden implementieren sollte als ein Fensterplugin oder beispielsweise ein Datenbankplugin).
Das konkrete Plugin was hier genutzt werden kann sieht nun so aus:
class XComGuiWin32 : public XComGuiBase { private: HWND hWindow; /*window handle*/ HWND m_hTree; bool b_keys [256]; /*array of key flags*/ XGuiMessageSystem* m_ptr_message; INITCOMMONCONTROLSEX m_comctrl; public: XComGuiWin32 (XGuiMessageSystem* ptr_message); ~XComGuiWin32 (void); /* callback methods */ static LRESULT CALLBACK window_proxy (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); /* window creation methods */ virtual int xMain (XGuiPrefences* ptr_render, XComRenderSpec* ptr_base, RENDERFUNC pfunc); virtual int xCreate (XGuiPrefences* ptr_render, int menu); virtual bool InitCommonControls (void); /* Child creation methods */ virtual int addButton (int x, int y, int cx, int cy, int id, char* name); virtual bool CreateTreeview (int x, int y, int cx, int cy, int id); /* Toolbox methods */ virtual int AddElementToTreeview (int nLocation, char* elem, bool sorted); /* utility methods */ virtual bool showConsole (bool is_shown); virtual void setKey (int key, bool state); virtual void InfoBox (char* message, char* title); virtual void ErrorBox (char* message, char* title); virtual XApplication getApplicationInstance (void); virtual XWindow getMainApplicationWindow (void) ; virtual XUnknown acceptVisitor (XComVisitor* tmp) { XUnknown test; memset (&test, 0, sizeof (XUnknown)); test.ptr_guibase = tmp->downcast(this); return test; } protected: };
Wie ihr seht, implementiert es alle Abstrakten Methoden von XComGuiBase. Meiner Meinung nach liegt hier ein generelles Verständnisproblem vor, deshalb poste ich alles mal ganz ausführlich. diese XWin32 Klasse ist unabhängig von der Anwendung, genauso wie die XDirectRender oder z.B. die XMesh3ds auch. Es sind alles Klassen, die in einer Dll sind und bei Bedarf geladen werden können. Es wäre jetzt möglich, zu sagen, die Anwendung soll die Dll's selber laden. Das soll allerdings der Pluginmanager übernehmen. Ich will ihn nicht groß mit Funktionalität füttern, er soll nur dem Zweck dienen, der Anwendung Code wie das Laden von Dll's zu erleichtern. Der Pluginmanager hat hierfür 2 Funktionen die ich oben schon erklärt habe.Allerdings ist der Pluginmanager nicht allmächtig. Eine fundamentale Schwäche, wo ich auch keine Lösung finde ist z.B. die erweiterbarkeit ohne Kompilierung. Da muss ich auch nochmal schaun.
Ich hoffe das war nun nicht zu viel
-
Hmmm,
ich habe nochmal darüber nachgedacht, aber irgendwie gefällt es mir nicht so wie es ist. Ich kann natürlich für jeden Plugintyp auch ne überladene Methode schreiben, allerdings wäre es sinnvoll, es so zu handhaben, dass der Manager nicht mehr Kompiliert werden muss, wenn neue Plugins hinzukommen.
Hat da jemand eine Idee wie man das regeln kann?
-
du braeuchtest fuer jede gruppe von plugins eine eigene methode,
also z.b. LoadGuiPlugin, LoadDBPlugin etc.
verschiedene plugins zusammenzuwuerfeln und von einer basisklasse
abzuleiten die eigentlich nichts gemeinsam bzw miteinander zu tun
haben ist schlecht.
also z.b. du machst fuer die 3 gruppen XComGuiBase,XComRenderSpec
und XComMesh je ne eingene methode.was ich nicht verstehe:
Eine fundamentale Schwäche, wo ich auch keine Lösung finde ist z.B. die erweiterbarkeit ohne Kompilierung
normalerweise ist es so, dass du fuer deine dll eine methode hast
(z.b. CreatePlugin) die gibt dir einen zeiger auf eine konkrete klasse
zurueck. dadurch ereichst du doch die erweiterbarkeit ohne neukompilierung
(natuerlich muessen die einzelnen plugin-dlls ja kompiliert werden
aber die hauptanwendung ja nicht).
-
na natürlich, die Plugins müssen auch nicht neu kompiliert werden aber der Manager....
Ich habe auch die verschiedenen Gruppen... allerdings muss ich um nen Plugin zu laden wissen
1.) Welche Basisklasse zu dem Plugin gehört
2.) Welche Dll zu dem Plugin gehört und damit auch
3.) Welches Plugin exakt geladen wirdDer Anwender braucht das nicht zu wissen, aber ich muss ja in bestimmter Weise darauf reagieren. Will ich jetzt zum Beispiel ein Plugin SQL hinzufügen mit der Basisklasse XComDatenbank, kann ich das Plugin SQL bequem übersetzten und es ist umabhängig. Aber ich muss um es einzubetten, den Pluginmanager auch neu kompilieren, da sonst das Plugin nicht zur verfügung steht.
Gruß Sebastian
-
wenn das so ablaeuft hast du nen groben designfehler!
das ganze sollte in etwa so aussehen:
Plugin* LadeDatenbankPlugin() { // funktionen des os DllHandle dll = LoadDll("irgendwas.dll"); DllFunction func = GetFuncAddress(dll,"CreatePlugin"); return func(); }
viel mehr sollte der plugin-manager nicht machen. der soll gar nicht
wissen was das plugin alles kann bzw. welche es gibt.
in deiner anwendung sind von einem plugin nur eine bestimmte
anzahl von methoden bekannt (definiert durch die basisklasse:
z.b. bei einem visuellen plugin eine methode show()).wenn du wissen musst welches konkrete plugin geladen wird
kannst du dir den ganzen mechanismus mit basisklasse etc sparen.
-
und wo kriege ich den namen der dll her? bei mir ist jedes konkrete Plugin in einer eigenen Dll... das heisst wenigstens den Dllnamen muss ich irgendwie bestimmen.
-
da gibts dann ja ne menge moeglichkeiten.
entweder du versuchst alle dlls in einem verzeichnis
zu laden oder du schreibst das in eine config datei oder
du laedst immer eine feste dll (z.b. das guid plugin heist immer
gui.dll).