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



  • 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



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


Anmelden zum Antworten