Zugriff auf Methoden abgeleiteter Klassen die allerdings nicht in der Basisklasse definiert sind mit Basisklassenzeiger
-
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
-
du übergibst queryinterface das neue interface,welches du benutzen willst, und queryinterface richtet dir je nach klasse alles ein, was gebraucht wird.
query interface macht nämlich eigentlich sogar noch viel mehr, da es sogar in manchen klassen dazu befähigt ist, das objekt selber zu ändern, je nachdem welches interface benutzt wird.also, du hast ein interface x und y.
x zeigt auf ein objekt, du willst nun aber, dass y auf das objekt zeigtx->doSth(); x->queryInterface("class",y); //y zeigt nun auf ein objekt y->doSth();
queryinterface geht eigentlich sogar noch einen stück weiter,aber das führt hier zu weit.
ansonsten benutzt du einfach deinen dynamic cast^^
-
ich weiss nicht ob ich es vielleicht nicht verstanden habe, aber:
mein Zeiger zeigt auf das richtige Objekt! nur wenn ich mit nem A* auf B zeige, und dann A* auf ein Objekt von B zeigt, habe ich noch nix gewonnen. Auf die Methoden von B kann ich auch dann nur zugreifen, wenn sie in A definiert sind, und das ist das problem.
-
auch wenn sie nicht so heisst meine QueryInterface methode sieht wahrscheinlich so aus:
unsigned long XComManager::registerPlugin (unsigned long plgID, XComBase* ptr_base, XGuiMessageSystem* ptr_message) { HMODULE hDll = (HMODULE) NULL; char* dllname = new char [100]; static int counter = 0; // GUI - Plugin laden if (plgID == PLG_GUI) { *mglog << "Plugin erkannt auf PLG_GUI" << endl; #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)); *mglog << "Neues Element in map eingefügt mit ID " << counter << endl; counter++; /* eigentlich Aufgabe der Anwendung */ dynamic_cast<XComGuiBase*>(ptr_base)->xCreate (ptr_pref, 0); dynamic_cast<XComGuiBase*>(ptr_base)->xMain (ptr_pref); #else //Lade Linuxpluigin #endif } // Render - Plugin laden else if (plgID == PLG_RENDER) { } return 0; }
Die XExport funktion für den fall kennt ihr ja schon....
-
fluxy schrieb:
ich weiss nicht ob ich es vielleicht nicht verstanden habe, aber:
mein Zeiger zeigt auf das richtige Objekt! nur wenn ich mit nem A* auf B zeige, und dann A* auf ein Objekt von B zeigt, habe ich noch nix gewonnen. Auf die Methoden von B kann ich auch dann nur zugreifen, wenn sie in A definiert sind, und das ist das problem.
ach ich gebs auf, du wirst es nicht kapieren, dass danach das übergebe(ein anderes!!!!) Interface auf B zeigt
-
ein anderes???? hmmm wie jetzt?
-
XComBase* a= new XComGuiWin32(); XComGuiBase* b; a->queryInterface("XComGuiBase",static_cast<void**>(&b)); b->InitCommonControls();
das poste ich hier jetzt zum 3. mal wenn dus jetzt nich verstehst, solltest dein projekt canceln
-
wieso soll ich ein Projekt canceln, nur wenn es mal Probleme gibt:
Also aus der QueryInterface methode entnehme ich, dass sie in dem Fall wie du sie grade aufrufst, ne exception wirft (weil du sie nicht mit IUnknown aufgerufen hast). Ist das so der Sinn???
-
das wirft keine exception, es wirft nur ne exception, wenn du a) ein interface übergibst, dass nicht compatibel mit der klasse ist, oder b) die klasse kein interface hat(in dx ist die einzige klasse die kein interface hat IUnknown, wovon jede andere klasse abgeleitet ist
also nochmal das ganze prinzip:
//kurzformat^^ class IUnknown;//hat die methode queryinterface, die wenn sie aufgerufen wird, ne exception wirft class derived:public IUnknown;//überschreibt queryInterface, sodass bestimmte typen akzeptiert werden,ansonsten wird das queryinterface von IUnknown benutzt class derived2:public derived;//überschreibt queryInterface von derived,auch hier werden wieder bestimmte interfaces akzeptiert, und wenns nich klappt, wird queryInterface von derived aufgerufen
ist also bei mir ein klassischer fall von rekursion, es wird schrittweise durch die vererbungen durchgegangen, und getestet, ob das übergebe Interface damit kompatibel ist.
-
okay jetzt habe ich das verstanden. allerdings hast du in deinem Beispiel als 2. Paramter für QueryInterface einen static_cast angegben der als Ziel nen XComGuiBase benötigt, also muss die anwendung trotzdem alle klassen kennen oder???
otze schrieb:
XComBase* a= new XComGuiWin32(); XComGuiBase* b; a->queryInterface("XComGuiBase",static_cast<void**>(&b)); b->InitCommonControls();
Die Frage war ja wie ich genau darauf verzichten kann...
-
du woltlest keinen dynamic cast, den static cast kannst du nicht verhindern,und ein static_cast ist wirklich nicht schlimm.
-
na1a eigentlich wollte ich jeden Cast auf die Zielklasse verhindern... obs jetzt nen static_cast oder nen dynamic_cast ist, ist mir eigentlich scheiss egal...
-
das wird kein cast auf die zielklasse, sodnern ein cast auf void**, und ich würde gerne mal erfahren, wo du ne klasse void** hast
-
XComGuiBase* b; a->queryInterface("XComGuiBase",static_cast<void**>(&b));
was machst du denn da? Du erzeugst zusätzlich zu dem Zeiger auf XComBase einen Zeiger auf XComGuiBase und übergibst diesen dem static_cast operator. Du sagst ihm lediglich dass er daraus nen void** machen soll, aber deine Quelle ist dein XComGuiBase pointer....
-
was hast du eigentlich gegen die c++ casts?
-
gegen die casts habe ich gar nix, finde sie sogar gut, aber die Anwendung darf die Klassen nicht kennen, das ist das problem. Und wenn du einen Cast machst, musst du immer etwas angeben, auf das du einen cast machst. Das ist das Problem. Die Folge daraus ist, dass die Anwendung nicht casten darf.
-
dh deine anwendung soll ein interface benutzen, ohne es zu kennen?
oder soll die anwendung nur die klasse nicht kennen, auf welche sich das interface bezieht? dann wäre ein cast nach void nicht schlimm, ansonsten wäre aber dein gesamtes unterfangen sinnlos, da man etwas, was man absolut nicht kennt, nicht benutzen kann
-
doch das Interface ist ja XComBase ..... okay andere Interfaces da kann man mit Leben das die Anwendung die kennen sollte.... aber wie sieht es mit den Klassen aus?? Die darf die Anwendung nicht mehr kennen, niemals. Und wenn ich jetzt in der Pluginklasse ne Methode habe, die im Interface nicht definiert ist habe ich doch schon wieder ein Problem oder?!
Also Interfaces ja, aber andere Klassen NEVER!
-
Allerdings wenn ich ein Template über Dll grenzen hinweg deklarieren könnte, wäre es vielleicht möglich die QueryInterface Methode so zu modifizieren, dass sie den Pointer zurückgibt....
oder?!
-
class XComBase { public: virtual unsigned long executeCommand (void) = 0; virtual unsigned long registerPlugin (void) = 0; virtual unsigned long unregisterPlugin (void) = 0; private: protected: }; /* 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: };
2 interfaces,für 2 aufgaben,wenn dir die interfaces die du dir für die jeweiligen klassen-und aufgaben-erstellst nicht ausreichen, hast du ein grundlegendes designproblem.
dh: entweder (mehrstufige) interfaces die dir für deine jeweiligen probleme die nötige funktionalität liefern,oder garkeine,denn dann machen die jeweiligen klassen ihre arbeit um längen besser.//edit zu deinem 2. post
noch einmal templates und virtual passen nicht zusammen, sobald du in einem interface eine virtual-template methode hast,funktioniert dein interface nichts mehr, UND du hast immernoch nichts von deinem interface verschleiert, wenn der compiler einen code compiliert, bei dem eine funktion einen typ x zurückgeben kann, so ist auch der user bemächtigt einen typ x zu erstellen und zu verwenden.klartext:
//header.h foo bar(){ return foo(); } //main.cpp int main{ foo=bar(); }