Zugriff auf Methoden abgeleiteter Klassen die allerdings nicht in der Basisklasse definiert sind mit Basisklassenzeiger



  • 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 mir

    hier, 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



  • 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 zeigt

    x->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


Anmelden zum Antworten