Fehler bei Funktionspointer einer Klasse



  • Hallo,
    ich arbeite aktuell an einer Klasse für meine SQLite abfragen und habe ein Problem mit dem sql Callback.

    Folgender Fehler tritt auf:

    IntelliSense: Das Argument vom Typ ""int (Engine::dataManager::*)(void , int, char **, char **)"" ist mit dem Parameter vom Typ ""int ()(void *, int, char **, char **)"" inkompatibel.

    Hier mal der Code :

    int (Engine::dataManager::*testVar) (void*, int, char**, char**);
    testVar= &sqlCallback;
    
    sqlite3_exec( Database , "select * from tiles;" , testVar, NULL , NULL);
    


  • Mach mal

    int (Engine::dataManager::*testVar) (void*, int, char**, char**);
    

    zu

    int (*testVar) (void*, int, char**, char**);
    

    dann sollte es gehen.
    EDIT:
    Die erste Variante ist ein Zeiger auf eine Memberfunktion, das willst du hier aber ja nicht.



  • Wenn ich

    int (*testVar) (void*, int, char**, char**);
    

    mache ,funktioniert das setzen der Variable nicht mehr .

    beliebigerVarname = &sqlCallback;
    

    gibt den Fehler

    1 IntelliSense: Ein Wert vom Typ ""int (Engine::dataManager::*)(void *Pointer, int argc, char **argv, char **columnNames)"" kann keiner Entität vom Typ ""int (*)(void *, int, char **, char **)"" zugewiesen werden.

    Also das hat schon seine berechtigung an dieser Stelle 🙄

    Habe schon verschiedene Sachen versucht, allerdings funktionierte keine dieser Versuche. Wenn ich in der Main eine funktion mit dem Callback mache funktioniert alles 1A. Nur wenn ich es als Methode einer Klasse versuche , funktioniert es nicht.

    Hoffe mein Problem ist verständlich.

    Hier mal ein Beispiel das funktioniert

    int Callback( void *Pointer, int argc, char **argv, char **columnNames)
    {
    //cout<< *argv <<endl;
    	for(int i = 0; i < argc; i++)
    	{
    		std::cout << argv[i] << std::endl;
    	}
    return 0;
    }
    
    int main()
    {
    	sqlite3* Database;
    	std::string Path;
    	if(sqlite3_open("engine_data.db", &Database) != SQLITE_OK)
    	{
    		std::cout << "Fehler beim Öffnen: " << sqlite3_errmsg(Database) << std::endl;
    	}
    	sqlite3_exec( Database , "select * from tiles;" , Callback , NULL , NULL);
    
    	sqlite3_close(Database);
    }
    


  • Du kannst keine nicht statische Memberfunktion übergeben. Du musst dein Objekt über den void* Parameter durchschleusen und in der Callbackfunktin casten.



  • manni66 schrieb:

    Du kannst keine nicht statische Memberfunktion übergeben. Du musst dein Objekt über den void* Parameter durchschleusen und in der Callbackfunktin casten.

    Wie kann ich das mit dem durchschleusen bewerkstelligen ?



  • Fujikatoma schrieb:

    manni66 schrieb:

    Du kannst keine nicht statische Memberfunktion übergeben. Du musst dein Objekt über den void* Parameter durchschleusen und in der Callbackfunktin casten.

    Wie kann ich das mit dem durchschleusen bewerkstelligen ?

    class myClass
    {
    int Callback( int argc, char **argv, char **columnNames)
    {
    //cout<< *argv <<endl;
        for(int i = 0; i < argc; i++)
        {
            std::cout << argv[i] << std::endl;
        }
    return 0;
    }
    };
    
    int Callback( void *Pointer, int argc, char **argv, char **columnNames)
    {
        myClass *myObject = (myClass*)Pointer;
    
        myObject->Callback( argc, argc, columnNames );
    }
    
    int main()
    {
        sqlite3* Database;
        std::string Path;
        myClass myObject;
    
        if(sqlite3_open("engine_data.db", &Database) != SQLITE_OK)
        {
            std::cout << "Fehler beim Öffnen: " << sqlite3_errmsg(Database) << std::endl;
        }
        sqlite3_exec( Database , "select * from tiles;" , Callback , &myObject , NULL);
    
        sqlite3_close(Database);
    }
    

    Ich hab jetzt mal geraten, wo beim Aufruf von sqllite3_exec die Adresse von myObject übergeben werden muß.

    mfg Martin



  • Danke für das Beispiel, das schaut auch im Primzip sehr gut aus.
    Allerdings war das nur ein Beispiel und ich arbeite NUR in der Klasse, ein Objekt der Klasse ist also nicht vorhanden.
    sqlite3_exec wird in einer Methode der Klasse aufgerufen

    Habe es jetzt so gelöst :

    #include "dataManager.h"
    #include <iostream>
    #include "sqlite3.h"
    
    Engine::dataManager::dataManager()
    {
    }
    
    int Engine::dataManager::sqlCallback(int argc, char **argv, char **columnNames)
    {
    	//Engine::dataManager::sqlArgs = argv;
    
    	return 0;
    }
    
    int Callback( void *Pointer, int argc, char **argv, char **columnNames)
    {
        Engine::dataManager *myObject = (Engine::dataManager*)Pointer;
    
        myObject->sqlCallback( argc, argv, columnNames );
    }
    
    int Engine::dataManager::loadSql(std::string path, void *Pointer)
    {
    	//int (Engine::dataManager::*beliebigerVarname) (void*, int, char**, char**);
    	//beliebigerVarname = &sqlCallback;
    
    	sqlite3* Database;
    	std::string Path;
    	if(sqlite3_open("engine_data.db", &Database) != SQLITE_OK)
    	{
    		std::cout << "Fehler beim Öffnen: " << sqlite3_errmsg(Database) << std::endl;
    	}
    
    	sqlite3_exec( Database , "select * from tiles;" , Callback , Pointer, NULL);
    
    	sqlite3_close(Database);
    
    }
    

    Nur leider Funktioniert das nicht so wirklich



  • Worauf zeigt deiner Meinug nach this?



  • Funktioniert jetzt alles 😉
    Danke für die Hilfe!



  • Fujikatoma schrieb:

    Danke für das Beispiel, das schaut auch im Primzip sehr gut aus.
    Allerdings war das nur ein Beispiel und ich arbeite NUR in der Klasse, ein Objekt der Klasse ist also nicht vorhanden.
    sqlite3_exec wird in einer Methode der Klasse aufgerufen

    Habe es jetzt so gelöst :

    #include "dataManager.h"
    #include <iostream>
    #include "sqlite3.h"
    
    Engine::dataManager::dataManager()
    {
    }
    
    int Engine::dataManager::sqlCallback(int argc, char **argv, char **columnNames)
    {
    	//Engine::dataManager::sqlArgs = argv;
    
    	return 0;
    }
    
    int Callback( void *Pointer, int argc, char **argv, char **columnNames)
    {
        Engine::dataManager *myObject = (Engine::dataManager*)Pointer;
     
        myObject->sqlCallback( argc, argv, columnNames );
    }
    
    int Engine::dataManager::loadSql(std::string path, void *Pointer)
    {
    	//int (Engine::dataManager::*beliebigerVarname) (void*, int, char**, char**);
    	//beliebigerVarname = &sqlCallback;
    
    	sqlite3* Database;
    	std::string Path;
    	if(sqlite3_open("engine_data.db", &Database) != SQLITE_OK)
    	{
    		std::cout << "Fehler beim Öffnen: " << sqlite3_errmsg(Database) << std::endl;
    	}
    
    	sqlite3_exec( Database , "select * from tiles;" , Callback , Pointer, NULL);
    
    	sqlite3_close(Database);
    
    }
    

    Nur leider Funktioniert das nicht so wirklich

    Wenn Du nicht mit Objekten arbeitest, was soll dann Dein cast in Zeile 19 bewirken?

    Ohne Objekte machst Du einfach Deine memberfunktionen statisch, dann kannst Du ihre Adresse auch direkt SQLite übergeben.

    Zum Verständniss:
    Der Unterschied zw, statischen Memberfunktionen oder einfachen Funktionen und normalen Memberfunktionen ist, daß letztere implizit als Parameter einen Zeiger auf das dazugehörige Objekt erhalten. Das ist nämlich der this-Zeiger.

    Aus

    myObject.myMember();

    macht der C++ Compiler sowas wie

    MY_CALSS::myMember( &myObject );

    Aus diesem Grund kannst Du einem normalen Funktionszeiger nicht die Adresse einer nicht-statischen Memberfunktion zuweisen, weil beim Aufruf der Funktion über den Zeiger this nicht mit übergeben wird. Eine statische Memberfunktion geht aber sehr wohl.

    Memberfunktionen, die nicht auf irgendwelche andere nicht statische member zugreifen müssen, sollten daher auch als statisch deklariert werden.

    mfg Martin



  • Danke für die Infos !
    Ich werde es bei meinem weiteren vorhaben beachten.
    Der oben gepostete Code funktioniert jetzt 1A , nachdem ich die return's hinzugefügt habe. 😋


Log in to reply