Zugriff auf Methoden abgeleiteter Klassen die allerdings nicht in der Basisklasse definiert sind mit Basisklassenzeiger
-
Hallo ich habe folgende Klassenanordnung:
/*Manager*/ class XComManager { public: XComManager (XGuiPrefences* ptr_pref); virtual ~XComManager (void); virtual unsigned long registerPlugin (unsigned long plgID, XComBase* ptr_base, XGuiMessageSystem* ptr_message); virtual unsigned long startPlugin (void); virtual unsigned long stopPlugin (void); virtual unsigned long releasePlugin (void); private: std::vector<XComBase*>plgStack; LOG* mglog; XGuiPrefences* ptr_pref; protected: }; /* Basisklasse von allem */ class XComBase { public: virtual unsigned long executeCommand (void) = 0; virtual unsigned long registerPlugin (void) = 0; virtual unsigned long unregisterPlugin (void) = 0; private: protected: }; Problem: 1.) Ich will mit einem Zeiger auf die Klasse XComBase auf die rein virtuellen Methoden von XComGuiBase zugreifen, die in XComGuiWin32 überschrieben werden. 2.) ich will keinen Cast verwenden, zum Beipspiel über RTTI den dynamic_cast 3.) es dürfen keine weiteren Klassen nach aussen sichtbar sein, die Anwendung muss also nen XComBase* übergeben, keinen anderen Zeigertyp! /* Basisklasse von guiplugin */ class XComGuiBase : virtual public XComBase { public: virtual int xCreate (XGuiPrefences* ptr_render, int menu) = 0; virtual int xMain (XGuiPrefences* ptr_render) = 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; private: protected: }; /* dll klassenbeispiel */ 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); 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); HINSTANCE getApplicationInstance (void) { return (HINSTANCE) GetModuleHandle (NULL); } HWND getMainApplicationWindow (void) { return (HWND) this->hWindow; } virtual unsigned long executeCommand (void); virtual unsigned long registerPlugin (void); virtual unsigned long unregisterPlugin (void); protected: };
Schonmal danke für Hilfe. Ich hoffe ich habe nicht zu große Ansprüche. Gruß Sebastian.
-
eine baseclass kann nur auf die methoden in der abgeleiteten klasse zugreifen,die in der baseclass als virtual declariert sind, mehr nicht.
du wirst um ein umcasten nich drumrumkommen. vielleicht als idee: du erlaubst nur das umcasten auf ein andres interface,nicht auf die derivedclass.btw: eine virtual public vererbung sollte bei interfaces nich vonnöten sein,d a reicht ne normale vererbung.
-
okay naja so war es auch gedacht eigentlich... war ich wohl bissl neben dem Wind.... Aber es gibt keine Möglichkeit auf die casts ganz zu verzichten?
-
nein leider nicht. und ein dynamic cast ist auch nicht so schlimm wie es einem immer weis gemacht wird.
-
Was auch noch geht ist statische Polymorphy einzusetzen. Geht aber bei weitem nicht überall und runtime Polymorphy ist hier eigentlich besser geeignet.
Ich geh mal davon aus, dass XComManager::registerPlugin auf die abgeleitete Klassen zugreifen muss. Also:
template<class T> XComManager::registerPlugin(T*t){ assert(typeid(*T)!=typeid(XComGuiWin32)); XComBase*base=t; //Um sicher zu stellen, dass man T zu XComBase upcasten kann //... } template<> XComManager::registerPlugin<XComGuiWin32>(XComGuiWin32*t){ //... }
Das ganze hat einen ganz gewaltigen Haken, der Upcast muss in registerPlugin geschehen. Wenn nicht dann wird das Template nicht spezialisiert und du hast die Sauerei, deshalb das assert.
-
hmmm ne das löst mein Problem ja auch nicht. Das Problem ist folgendes. Die Zeiger werden im Manager natürlich auf ein spezielles Objekt gesetzt, das von vorn herein nicht feststehen muss. So wie es jetzt ist, machen die casts nix weil sie im Manager sind, aber das muss normalerweise die Anwendung machen die den Manager anspricht. Und die dürfen keine weiteren Klassen kennen ausser XComBase... deswegen können sie auch den Cast nicht machen.
Gruß Sebastian
-
hmmm ich habe vielleicht selber eine kleine Idee. Allerdings fällt mir nicht ein, wie ich das mit dem Rückgabetyp machen sollte. Ich könnte ja in XComBase eine weitere rein virtuelle methode z.B. mit dem namen GetPluginType () machen, die dann von den Plugins überschrieben werden muss und auf die man von der Anwendung zugreifen kann. Die muss dann natürlich den richtigen zeigertyp zurückgeben. Allerdings wie mache ich das mit dem Rückgabetyp? Kann ich da vielleicht ne enum oder struct zurückliefern, um den Rückgabetyp der Funktion variable zu halten oder was muss ich da machen?
Der Aufruf der Methode in der Hauptanwendung würde damit folgende Form annehmen:
ptr_manager = new XComManager (&wpref); ptr_manager->registerPlugin (PLG_GUI, ptr_gui, this); XComBase* test = ptr_manager->GetPlugin (0); test->GetpluginTyp()->xCreate (); test->GetPluginTyp()->xMain ();
-
geht net,da templates und virtual ja nicht zusammenpasst, und solche strukturen die nen variablen typ speichern müssten,müssten selber templates enthalten^^
aber schau dir mal diese funktion an:
HRESULT QueryInterface( REFIID riid, LPVOID *ppvObj );
das is ne methode in directx.
erster parameter isn einfacher string, in der du den namen des gewünschten interface eingibst, und der 2. parameter ist ein zeiger auf das interface, welches du in zukunft verwenden willst. Der returnwert gibt true zurück, wenn die klasse für die queryinterface aufgerufen wurde von dem im 2. parameter übergebenen interface abgeleitet wurde.das wäre zb:
XComBase* a= new XComGuiWin32(); XComGuiBase* b; a->queryInterface("XComGuiBase",static_cast<void**>(&b)); b->InitCommonControls();
ich würde aber statt returnwert ne gute alte exception benutzen
-
[quote="fluxy"]Hallo ich habe folgende Klassenanordnung:[quote]
zu groß, kapier ich net.1.) Ich will mit einem Zeiger auf die Klasse XComBase auf die rein virtuellen Methoden von XComGuiBase zugreifen, die in XComGuiWin32 überschrieben werden.
2.) ich will keinen Cast verwenden, zum Beipspiel über RTTI den dynamic_cast
3.) es dürfen keine weiteren Klassen nach aussen sichtbar sein, die Anwendung muss also nen XComBase* übergeben, keinen anderen Zeigertyp!klingt nach nem interessanten problem.
reduziere den code auf's nötigste (wens geht mit Klassen wie Baum und Auto, nicht Foo und Bar) und liefere ne main() mit, damit ich testen kann und ich mach mich an die arbeit.
edit: nicht nötig, otze hat ja ne gute lösung.
-
virtual und templates gehen nicht? warum?!
-
1. schau in meinen alten post, da is ne anständige lösung(das wurde von DX gut gelöst^^)
2. wieso funktionieren templates+virtual nicht?class a{ template<class T> virtual T foo(T)=0;//fehler }
die templates muss werden zur compilezeit erstellt,virtual aber erst bei der ausführung des Programmes, durch virtual weis der compiler also nicht, was für typen er zur compiletime erstellen muss.
-
naja also ich habe mal was versucht auf die schnelle zusammenzustellen. Du brauchst dazu noch so nen Manager, der die Klassen verwaltet, das soll die Anwendung selber ja nicht machen. Ich habe mal einfach Fahrzeuge weiter spezifiziert (aufteilung in Auto und Flugzeug und dann spezielle Objekte gemacht wie Porsche, VW und LTU.
Das mit dem Manager regeln wir am besten per Email. Kannst mir ja dann mal eben ne Email schreiben. Hier erstmal die Klassenhierachie...
/* interface mit methoden die für jedes FAHRZEUG dienen also für alles */ public class Fahrzeug { public: virtual void drive () = 0; virtual void go_into () = 0; virtual void repare () = 0; private: protected: }; /* Interface mit Methoden die nur für jedes Auto dienen */ public class Auto : public Fahrzeug { public: virtual void getWheels () = 0; virtual void getEnginePower () = 0; virtual void getqcm () = 0; virtual void ledersitze () = 0; private: protected: }; /* Interface mit Methoden die nur für jedes Flugzeug dienen */ public class Flugzeug : public Fahrzeug { public: virtual void getFluegel () = 0; virtual void getNeededSprit () = 0; virtual void isFlyingPersonalNice () = 0; virtual void sexOnFylingCabine () = 0; private: protected: }; /* Implementierungsklasse LTU Flugzeug */ public class LTU : public Flugzeug { public: LTU (); virtual ~LTU (); virtual void drive (); virtual void go_into () ; virtual void repare () ; virtual void getFluegel () ; virtual void getNeededSprit () ; virtual void isFlyingPersonalNice () ; virtual void sexOnFylingCabine () ; private: protected: }; /* Implementierungsklasse anderes flugzeug */ public class MyAirLine : public Flugzeug { public: MyAirLine (); virtual ~MyAirLine (); virtual void drive (); virtual void go_into () ; virtual void repare () ; virtual void getFluegel () ; virtual void getNeededSprit () ; virtual void isFlyingPersonalNice () ; virtual void sexOnFylingCabine () ; private: protected: }; public class Porsche : public Fahrzeug { public: virtual void getWheels () ; virtual void getEnginePower () ; virtual void getqcm () ; virtual void ledersitze (); virtual void drive () ; virtual void go_into () ; virtual void repare () ; private: protected: }; public class VW : public Fahrzeug { public: virtual void getWheels () ; virtual void getEnginePower () ; virtual void getqcm () ; virtual void ledersitze (); virtual void drive () ; virtual void go_into () ; virtual void repare () ; private: protected: };
die main müsste dann in etwa so aussehen:
int main (void) { Manager* bla = new Manager (); Fahrzeug* bla = NULL; bla->start (&bla, ...); //hier fangen die Probleme an bla->ledersitze (); return 0; }
-
wo ist denn dein alter post? suchen geht ja net....
-
und sowas wie templates zur laufzeit gibbet net?
-
nein
mein alter post is hier auf seite 1 der letzte von mirhier, damit du nich suchen must:
aber schau dir mal diese funktion an:
HRESULT QueryInterface( REFIID riid, LPVOID *ppvObj );
das is ne methode in directx.
erster parameter isn einfacher string, in der du den namen des gewünschten interface eingibst, und der 2. parameter ist ein zeiger auf das interface, welches du in zukunft verwenden willst. Der returnwert gibt true zurück, wenn die klasse für die queryinterface aufgerufen wurde von dem im 2. parameter übergebenen interface abgeleitet wurde.das wäre zb:
XComBase* a= new XComGuiWin32(); XComGuiBase* b; a->queryInterface("XComGuiBase",static_cast<void**>(&b)); b->InitCommonControls();
ich würde aber statt returnwert ne gute alte exception benutzen
-
was macht denn da der static_cast? Und was muss dann die QueryInterface Methode machen?
Sry, aber deinen Thread finde ich nicht nur einen anderen von dir, aus 3 Beiträgen zur Einschränkung der Vererbung...
Gruß Sebastian.
-
keinen thread, der post den ich hier gepostet+gepastet hab, hab ich gemeint...
queryInterface funktioniert in etwa wie ein dynamic cast,intern kenn ich den code nicht, ein dynamic_cast kanns nich sein,aber ich vermute, dass es so aussieht://bei statischer polymorphie: IUnknown{ public: virtual void queryInterface(std::string Type,void** Pointer){ throw("cannot cast);//iunknown hat keine baseclass,man kann davon also nicht casten } }; class Derived:public IUnknown{ public: virtual void queryInterface(std::string Type,void** Pointer){ if(Type=IUnknown){ *Pointer=this; } else { IUnknown::queryInterface(Type,Pointer); } } };
ich gebe keine garantie, dass dies vollständig oder richtig ist, dass sind halt die überlegungen aus 5 minuten vorm nudeltopf stehen
ps:der static_cast ist da, um von dem zeiger nach void** zu casten.
-
Schau dir das Component Object Model an. Die Erklärungen von otze sind ja grauenhaft.
-
naja ich sehe grade das das ganze für mich gar nix bringt... Du machst dort ja nix weiter als nen Objekt. Das Objekt mache ich ja auch schon über meinen XComBase Zeiger das ist ja kein Problem. Es geht drum das ich Zugriff brauche auf meine anderen Klassen über diesen pointer oder habe ich irgendwas verpasst?!
-
Also in dem beispiel wird ja nur das Objekt erzeugt, auf das der Pointer zeigen soll. Dazu habe ich bei mir ja in jeder Dll eine Funktion, die das übernimmt:
Beispiel Win32 - Gui dll:
extern "C" __declspec (dllexport) void XExport (HINSTANCE hdll, XComBase** ptr_base, XGuiMessageSystem* ptr_message) { *ptr_base = new XComGuiWin32 (ptr_message); }
Also es geht hier gar nicht um das Objekt, was erzeugt werden muss. Das es vorher erzeugt werden muss ist klar, aber das erledigt eh der Manager, von welchem zuerst die Methode registerPlugin aufgerufen werden muss
#ifdef WIN32 strcpy ((char*)dllname, (char*)"dll"); strcat ((char*)dllname, (char*)"\\XWin32.dll"); *mglog << "Betriebsystem erkannt auf >>WINDOWS<<" << endl; if (!(hDll = LoadLibraryEx (dllname, NULL, 0))) { *mglog << "Error binding Dll to application's address space" << endl; } /* Zeiger auf die richtige Klasse initialisieren und dann im Pluginvektor abspeichern, damit die Anwendung darauf zugreifen kann */ GUI_PLG gplg = NULL; gplg = (GUI_PLG) GetProcAddress (hDll, "XExport"); gplg (hDll, &ptr_base, ptr_message); plgStack.insert(make_pair (counter, ptr_base));
Erst hiernach sollen die Methoden des Plugins zur Verfügung stehen.Da ich aber mit einem XComBase* auf beispielsweise ein XWin32 Objekt zugreife, bekomme ich die Methoden auf die weise nicht mehr; sie sind in XComBase ja nicht definiert.
Bitte sagt mir jetzt wie die oben genannte QueryInterfacemethode mir da helfen kann....
Gruß Sebastian