Zugriff auf Methoden abgeleiteter Klassen die allerdings nicht in der Basisklasse definiert sind mit Basisklassenzeiger
-
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(); }
-
otze schrieb:
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
Falscher cast...
-
Na schön... Also der Anwendung Zugriff auf alle Interfaces zu geben kann ich eventuell noch mit leben...
Allerdings sehe ich das nur als Verschiebung des Problems. Denn, was mache ich, wenn jetzt eine Pluginklasse, die Beispielsweise von XComGuiBase abgeleitet ist, eine Methode definiert, die in dem Interface nicht vorhanden ist. Dann komm ich auch mit einem Zeiger auf XComGuiBase nicht mehr weiter, sondern muss dann auf die spezielle Klasse casten.
Jetzt mal was spricht dagegeben: Die Anwendung darf von den Klassen nix wissen. Wenn Sie davon wissen, ist die Kapselung komplett im Eimer und der Vorteil der Plugins verschwindet damit. Der Vorteil ist ja grade, dass die Anwendung von den Klassen nix wissen braucht.
Und was den Cast angeht: ich weiss jetzt nicht obs der richtige Cast ist, aber in dem Fall kann ich auch direkt nen dynamic_cast machen. Ob ich jetzt meinen Zielpointer auf void** caste oder direkt nen Cast auf die Zielklasse angebe ist doch eigentlich egal. Im Prinzip finde ich die zweite Möglichkeit in dem Fall sogar noch besser, weil dort 1 Schritt weniger ausgeführt werden muss.
-
es heißt "double dispatching" oder "patern Visitor":
class XComBase; class XComGuiBase; class XComGuiWin32; class IXComVisitor { public: virtual void accept(XComBase * comBase) = 0; virtual void accept(XComGuiBase * comGuiBase) = 0; virtual void accept(XComGuiWin32 * comGuiBase) = 0; }; class XComBase { public: virtual visit(IXComVisitor *visitor) { visitor->accept(this); } }; class XComGuiBase : public XComBase { public: virtual visit(IXComVisitor *visitor) { visitor->accept(this); } }; class XComGuiWin32 : public XComGuiBase { public: virtual visit(IXComVisitor *visitor) { visitor->accept(this); } }; class XComManager : private IXComVisitor { public: virtual unsigned long registerPlugin (unsigned long plgID, XComBase* ptr_base) { ptr_base->visit(this); } private: void accept(XComBase * comBase) { } void accept(XComGuiBase * comGuiBase) { } void accept(XComGuiWin32 * comGuiBase) { } };
-
fluxy schrieb:
Na schön... Also der Anwendung Zugriff auf alle Interfaces zu geben kann ich eventuell noch mit leben...
du musst es sogar erlauben, da du die klasse sonst nicht verwenden könntest
Allerdings sehe ich das nur als Verschiebung des Problems. Denn, was mache ich, wenn jetzt eine Pluginklasse, die Beispielsweise von XComGuiBase abgeleitet ist, eine Methode definiert, die in dem Interface nicht vorhanden ist. Dann komm ich auch mit einem Zeiger auf XComGuiBase nicht mehr weiter, sondern muss dann auf die spezielle Klasse casten.
wie wärs mit nem speziellen interface für die jeweiligen klassen?
Jetzt mal was spricht dagegeben: Die Anwendung darf von den Klassen nix wissen. Wenn Sie davon wissen, ist die Kapselung komplett im Eimer und der Vorteil der Plugins verschwindet damit. Der Vorteil ist ja grade, dass die Anwendung von den Klassen nix wissen braucht.
erklär mir mal, wie du eine klasse auch nur irgendwie benutzen willst, wenn du der anwendung nichmal erlauben willst, das interface zu kennen.
der sinn solch eines plugin systems ist, eine reihe spezieller interfaces zu bieten, nach denen sich die plugins zu richten haben, nicht das system welches die plugins verarbeiten muss.
du hast normalerweise nur 2 möglichkeiten: variables front end, oder variables back end, beides zusammen kann nicht klappen.dh: du lädst ein GUI plugin.
die klassen kannst du über interfaces+factory classes benutzen. nun muss sich das plugin danach richten,wie du die interfaces aufgebaut hast, denn nur so ist eine allgemeine benutzbarkeit möglich, und nur so hat man überhaupt die möglichkeit, 2 plugins austauschen zu können.wenn die plugins nicht garantieren können, dass sie über deine standardinterfaces problemlos zu benutzen sind, dann ist es ein fehler des plugins.
aber eins ist klar, die standardinterfaces müssen deiner anwendung und dem plugin bekannt sein, denn sie dienen als verbindung, ohne diese verbindungen bist du absolut aufgeschmissen.
Und was den Cast angeht: ich weiss jetzt nicht obs der richtige Cast ist, aber in dem Fall kann ich auch direkt nen dynamic_cast machen. Ob ich jetzt meinen Zielpointer auf void** caste oder direkt nen Cast auf die Zielklasse angebe ist doch eigentlich egal. Im Prinzip finde ich die zweite Möglichkeit in dem Fall sogar noch besser, weil dort 1 Schritt weniger ausgeführt werden muss.
kommt ganz auf den zweck an, manchmal reicht ein simpler dynamic_cast nicht,vorallem wenn sich die objekte auf die das interface zeigen soll danach richten, mit welchem interface sie ausgeführt werden,mit einem queryInterface ist man auf jedenfall auf der sicheren seite,da da der ersteller des plugins entscheiden kann, was passieren wird, bei einem dynamic cast ist dies nicht möglich.
@ssm und bei jeder code erweiterung muss man dann in 2 klassen veränderungen tätigen?
-
hmmm also das von ssm.... cool..... aber Ohne kommentar verstehe ichs wohl nicht.
Kannst du es vielleicht mal erläutern?!
-
otze schrieb:
@ssm und bei jeder code erweiterung muss man dann in 2 klassen veränderungen tätigen?
ja, aber bu brauchst in diesem Fall keinen dynamic_cast zu machen. es ist dir zu entscheiden, was besser ist :p
"double dispatching" soll aber schneller arbeiten
-
Das Interface habe ich. Aber um es mal ganz klas auszudrücken ein anderer Fall. Angenommen wir haben nur 1 Interface für das Plugin
class Basis { public: virtual void test (void) = 0; };
und die Pluginklasse definiert eine andere methode die nicht im Interface sein darf:
class Abgeleitet { public: virtual void irgendwas (void); };
und ich habe jetzt meinen Baisklassenzeiger:
Basis* test = new Abgeleitet ();
wie bekomme ich jetzt ohne von der Klasse Abgeleitet zu wissen Zugriff auf die Mentode irgendwas???
-
das system is einfach:
du übergibst registerplugin einen nach XComBase* konvertierbaren pointer.
innerhalb der funktion wird dann versucht die richtige version von accept aufzurufen,accept macht dann irgendetwas mit dem pointer,je nachdem wie die implementierung ist@ssm jo das is richtig, ich wollte ja auch nie nen dynamic cast verwenden :p
-
fluxy schrieb:
hmmm also das von ssm.... cool..... aber Ohne kommentar verstehe ichs wohl nicht.
Kannst du es vielleicht mal erläutern?!
es ist mir ein bischen schwierig auf Deutsch zu erläutern, weil ich noch nich besonders fit in Deutsch bin. du kannst über pattern Visitor z.B. im Internent lesen:
http://kilana.unibe.ch:9090/ese2003gruppen-smallwikis/southsidecrewssc/patternserklrt/visitor/
wenn du weiter die Fragen hast, kann ich versuchen es zu erklähren
-
otze schrieb:
das system is einfach:
du übergibst registerplugin einen nach XComBase* konvertierbaren pointer.
innerhalb der funktion wird dann versucht die richtige version von accept aufzurufen,accept macht dann irgendetwas mit dem pointer,je nachdem wie die implementierung ist@ssm jo das is richtig, ich wollte ja auch nie nen dynamic cast verwenden :p
genau, das hab ich vergessen.
es gibt noch bessere Lösung, von Andrey Aleksandrevsku.
-
Der Sinn dieser Kapselung ist, dass Du keinen! Zugriff auf die Methode irgendwas bekommst. Um die Methode irgendwas aufzurufen kann Dein Plugin aber die Methode test (oder irgendeine andere passende virtuelle Methode des Interface) überschreiben und von dort aus selbst die Methode irgendwas aufrufen.
Vielleicht ist es so verständlicher ?
DJohn
EDIT: zu langsam. Das bezieht sich auf das letzte Beispiel von fluxy