Methodenaufrufe speichern



  • Hi,

    ich weiss garnicht ob das überhaupt in C++ vorgesehen ist aber ich will, so mein Gedanke zumindestens, ein Methodenaufruf speichern so das man die verknüpften Methoden später wieder aufrufen kann.

    Also ich will sowas wie im Pseudocode in der Art machen können:

    class foobar
    {
    public:
             void register();
             void proc(int);
             void func(std::string);
    };
    
    void foobar::register()
    {
      container->append("foo", int, void proc(int));
      container->append("hello", std::string, void func(std::string));
    }
    //...
    
    void anywhrere::update(std::string name)
    {
      if (name == "foor")
           container->method(container->param); // Aufruf von proc(int) mit dem abgespeicherten Parameter int
      else if(name == "hello")
           container->method(container->param); // Aufruf von func(std::string) mit dem abgespeicherten Parameter std::string
    }
    

    Ist das so überhaupt möglich oder gibt es vielleicht ein Design Pattern dazu? 😕

    Gruss,
    xmarvel



  • suchst du sowas wie boost::bind?



  • ich weiss gar nicht ob das überhaupt in C++ vorgesehen

    Ist vorstehen siehe Funktionspointer (C) bzw. Funktoren/Funktionsobjekte (C++).
    🙂


  • Administrator



  • Danke für die vielen Antworten.
    Hab mir jetzt alles durchgelesen und wie ich sehe funktioniert es doch nicht so wie ich gedacht habe da ich ja unterschiedliche Parameter für die Funktionen habe und diese nicht alle gleich sind aber das ist ja eine Vorrausetzung für die Funktionsobjekte.
    Oder gibt es dafür ein Ausweg vielleicht mit Templates oder Macros?

    Gruss,
    xmarvel



  • eine möglichkeit wäre die paramter in einer string map zu übergeben, du müsstest die werte halt wieder in integer, floats etc. umwandeln. die ogre engine macht das zum beispiel so ...



  • Bei Funktionsobjekten kann man die Member-Variablen als Parameter für die eigentliche Funktion benutzen....

    Somit lassen sich x beliebig viele auch von Objekt zu Objekt unterschiedliche Parameter verarbeiten, wenn man eine Schnittstellen-Klasse verwendet.

    Außerdem hat dies den Vorteil, dass man die Parameter mitspeichert... 😃



  • Hi!

    Mal eine Überlegung:

    class BaseClass;
    
    typedef void ( BaseClass::*eventCallback_t )( void );
    
    class EventFunc
    {
    public:
    	const char *name;
    	eventCallback_t	func;
    };
    
    class BaseClass
    {
    	enum { EVENT_MAX_ARGS = 3 };
    
    public:
    	static EventFunc	eventCallbacks[];
    
    public:
    	bool Call( const char *name )
    	{
    		return CallArgs( name, 0 );
    	}
    
    	template< class Arg1 >
    	bool Call( const char *name, Arg1 arg1 )	
    	{
    		return CallArgs( name, 1, arg1 );
    	}
    
    	template< class Arg1, class Arg2 >
    	bool Call( const char *name, Arg1 arg1, Arg2 arg2 )
    	{
    		return CallArgs( name, 2, arg1, arg2 );
    	}
    
    	template< class Arg1, class Arg2, class Arg3 >
    	bool Call( const char *name, Arg1 arg1, Arg2 arg2, Arg3 arg3 )
    	{
    		return CallArgs( name, 3, arg1, arg2, arg3 );
    	}
    
    	bool CallArgs( const char *name, int numargs, ... )
    	{	
    		int data[ EVENT_MAX_ARGS ];
    		va_list args;
    
    		va_start( args, numargs );
    
    		for ( int i = 0; i < numargs; ++i )
    		{
    			data[ i ] = ( int )va_arg( args, int * );
    		}		
    
    		va_end( args );
    
    		return CallArgsPtr( name, numargs, data );
    	}
    
    	bool CallArgsPtr( const char *name, int numargs, int *data )
    	{
    		EventFunc *p = Find( name );
    		eventCallback_t callback;
    
    		if ( !p )
    			return false;
    
    		callback = p->func;
    
    		switch ( numargs )
    		{
    		case 0:
    			( this->*callback )();
    			break;
    
    		case 1:
    			typedef void ( BaseClass::*eventCallback_1_t )( const int );
    			( this->*( eventCallback_1_t )callback )( data[ 0 ] );
    			break;
    
    		case 2:
    			typedef void ( BaseClass::*eventCallback_2_t )( const int, const int );
    			( this->*( eventCallback_2_t )callback )( data[ 0 ], data[ 1 ] );
    			break;
    
    		case 3:
    			typedef void ( BaseClass::*eventCallback_3_t )( const int, const int, const int );
    			( this->*( eventCallback_3_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ] );
    			break;
    
    		default:
    			std::cout << "unknown number of arguments\n";
    			return false;
    		}
    
    		return true;
    	}
    
    	EventFunc *Find( const char *name ) const
    	{
    		int i = 0;
    		EventFunc *p = NULL;
    
    		while ( true )
    		{
    			p = &eventCallbacks[ i ];
    
    			if ( !p->func )
    				break;
    
    			if ( !strcmp( p->name, name ) )
    				return p;
    
    			i++;
    		}
    
    		return NULL;
    	}
    
    	// test fkt
    	void Foo() const
    	{
    		std::cout << "Foo" << std::endl;
    	}
    
    	void Add( int x, int y ) const
    	{
    		int res = x+y;
    		std::cout << res << std::endl;
    	}
    
    	void Print( const char *str ) const
    	{
    		std::cout << str << std::endl;
    	}
    };
    
    EventFunc BaseClass::eventCallbacks[] = 
    {
    	{ "Foo", ( void ( BaseClass::* )( void ) )( &BaseClass::Foo ) },
    	{ "Add", ( void ( BaseClass::* )( void ) )( &BaseClass::Add ) },
    	{ "Print", ( void ( BaseClass::* )( void ) )( &BaseClass::Print ) },
    	{ NULL, NULL }
    };
    
    int main( void )
    {
    	BaseClass cls;
    	cls.Call( "Print", "Hallo Welt" );
    	cls.Call( "Add", 10, 20 );
    	cls.Call( "haha", 50 );
    
    	return 0;
    }
    

    Unten ist ein Anwendungsbeispiel. Aber Achtung: dieser Quellcode ist nicht besonders ausgereift, von wegen Exceptionhandling und sonstigen Sicherheitsvorkehrungen! Noch dazu werden Rückgabewerte nicht berücksichtigt... 🙂 Er soll nur einen simplen Lösungsansatz darstellen.

    grüße 🙂



  • @David_pb

    danke für dein Beispielcode hat mir sehr weitergeholfen

    @Mathias

    hmm... na mehrmaligen durchlesen weiss ich nicht was du meinst kannst du das vielleicht mit ein kurzen beispiel klar machen.

    @gast4646544846

    danke für den Hinweis.
    Hab mir mal mit Hilfe euer Ideen mir ein Beispiel Code zusammengebastelt wundert euch nicht das es Qt ist später soll das mit den Qt Libs funktionieren. Aber das Prinzip ist bleibt ja C++. 🙂

    Also hier mein Testcode zum rumspielen:

    #include <QtCore>
    
    class MyOtherMethods
    {
      public:
    	void showOtherString(QString s)
    		{
    			qDebug("String Other Out: %s", s.toStdString().c_str());
    		};
    	void showOtherQLine(QLine l)
    		{
    			qDebug("Line Out: x: %i y: %i", l.x1(), l.y1());
    		};
    };
    
    class MyMethods
    {
    	public:
    		void showString(const QString& s)
    		{
    			qDebug("String Out: %s", s.toStdString().c_str());
    		};
    
    		void showInt(int i)
    		{
    			qDebug("Int Out: %i", i);
    		};
    };
    
    class Container
    {
      public:
    	template <class T, class Z>
    	void call(QVariant value, void (T::*func)(Z))
    	{
    		qDebug("Type Name: %s", value.typeName());
    		T instance;
    		(instance.*func)(qVariantValue<Z>(value));
    	};
    };
    
    int main()
    {
     Container con;
     con.call("Hello World", &MyMethods::showString); // hier bricht er ab wegen dem const QString& als Parameter
     con.call(20, &MyMethods::showInt);
     con.call("FOOBAR", &MyOtherMethods::showOtherString);
     con.call(QLine(2,5,100,150), &MyOtherMethods::showOtherQLine);
    
     return 0;
    }
    

    Es funktioniert soweit auch schon ganz gut das einzigste Problem ist wenn der Parameter als Reference deklariert ist. Dann lässt es sich nicht mehr compilieren da er den Pointer anscheinend nicht mehr konvertiert bekommt 😞

    Hier die Fehlermeldung vom Compiler:

    Scanning dependencies of target func
    Building CXX object CMakeFiles/func.dir/main.o
    /opt/Trolltech-Qt4.2/include/QtCore/qvariant.h: In function ‘T qvariant_cast(const QVariant&) [with T = const QString&]’:
    /opt/Trolltech-Qt4.2/include/QtCore/qvariant.h:637:   instantiated from ‘T qVariantValue(const QVariant&) [with T = const QString&]’
    /home/xmarvel/Funktionsobjekte/main.cpp:38:   instantiated from ‘void Container::call(QVariant, void (T::*)(Z)) [with T = MyMethods, Z = const QString&]’
    /home/xmarvel/Funktionsobjekte/main.cpp:47:   instantiated from here
    /opt/Trolltech-Qt4.2/include/QtCore/qvariant.h:624: error: forming pointer to reference type ‘const QString&’
    /opt/Trolltech-Qt4.2/include/QtCore/qvariant.h:626: error: forming pointer to reference type ‘const QString&’
    /opt/Trolltech-Qt4.2/include/QtCore/qvariant.h:628: error: ‘t’ declared as reference but not initialized
    /opt/Trolltech-Qt4.2/include/QtCore/qvariant.h:629: error: invalid conversion from ‘const void*’ to ‘void*’
    /opt/Trolltech-Qt4.2/include/QtCore/qvariant.h:629: error:   initializing argument 3 of ‘bool qvariant_cast_helper(const QVariant&, QVariant::Type, void*)’
    /opt/Trolltech-Qt4.2/include/QtCore/qvariant.h:632: warning: returning reference to temporary
    make[2]: *** [CMakeFiles/func.dir/main.o] Fehler 1
    make[1]: *** [CMakeFiles/func.dir/all] Fehler 2
    make: *** [all] Fehler 2
    

    kann ich das umgehen ohne das ich bei der Methode showString den Parameter ändere?

    Gruss,
    xmarvel



  • xmarvel schrieb:

    Hab mir mal mit Hilfe euer Ideen mir ein Beispiel Code zusammengebastelt wundert euch nicht das es Qt ist später soll das mit den Qt Libs funktionieren. Aber das Prinzip ist bleibt ja C++. 🙂

    Schon, nur liegt der Fehler bei QVariant.

    mfg.



  • na da wirft mir Qt ja Steine in den Weg 🤡 dann muss ich meine Idee anscheinend irgendwie anders angehen.
    Aber danke an Alle für die Unterstützung.

    Gruss,
    xmarvel


Anmelden zum Antworten