Passing function pointer



  • Hi, this is my first post in this forum, so i am not sure General and Desktop is the right place for it.
    Let me know, if it will be moved.

    I am working on an application that uses a 3D engine. The engine has a C sdk, so until now everything went well, more or less.
    Now i would like to use a statement of the engine that requires a function pointer as a parameter casted to void *. Like this in MyClass.cpp:

    MyClass::constructor() {
    ...
    }
    
    MyClass::do_this() {
    ...
    create_someth(par1, par2, (void *) function ptr, par4);
    ...
    }
    

    I had a function, also in this class, for passing like this:

    void myFunc(int p1, long p2) {
    first_line;
    second_line;
    }
    

    In the header of my class there is definition of my function:

    ...
    public:
    ...
    void myFunc(int, long);
    ...
    

    So, how should look like the proper function pointer passing in this line:

    create_someth(par1, par2, (void *) function ptr, par4);
    

    Thanks in advance.


  • Qt Champions 2016

    A function pointer is the address to the function in the .text part of the binary. Global functions and class static functions are exactly the same, because they don't carry the this pointer. They can be passed directly as callbacks. Whereas class methods and virtual methods can't they need to be bound to an object. The address of the function (as anything in C++) is given by its name, quite literally:

    class MyClass
    {
    public:
        static int someFunction(char * param1, int param2);
    }
    
    typedef int (*FunctionType)(char *, int); //< We call the pointer to function type FunctionType (the line is optional and for simplicity).
    FunctionType pointerToFunction = &MyClass::someFunction; //< Literally means get the address of MyClass::someFunction and save it in the pointerToFunction variable.
    

    To finish up anything that's of pointer type can be implicitly converted to void *, so you can use:

    create_someth(par1, par2, &MyClass::someFunction, par4);
    

    directly.



  • Thanks for the really quick reply. It is great!

    Unfortunately, it don't want to work. I have got the following message:
    cannot convert 'void (MyClass::)(int, long)' to 'FunctionType {aka int ()(int, long)}' in initialization

    I thought maybe the type of the typedef wrong so i changed that from int to void. It is a bit better, i think but the message is just a little bit different:
    cannot convert 'void (MyClass::)(int, long)' to 'FunctionType {aka void ()(int, long)}' in initialization

    I hope you have the solution.


  • Qt Champions 2016

    @CCRfan said in Passing function pointer:

    Unfortunately, it don't want to work. I have got the following message

    Could you post the code that generates that error - the function definition, the function declaration and the line where you get the pointer and use it?



  • I don't know why changed the forum engine this:
    aka int (*)
    to this:
    aka int()
    Should i use a formatting mechanism?


  • Qt Champions 2016

    Yes, most certainly. See this thread.



  • The name of the function what i would like pass is: buttonClicked
    Important part from the class header file, with function declaration:

    class A8GS_Widget : public QWidget
    {
        Q_OBJECT
    public:
        explicit A8GS_Widget(QWidget *parent = 0);
        ~A8GS_Widget();
        LPDIRECT3D9 m_pD3D;
        LPDIRECT3DDEVICE9 m_pd3dDevice;
        ENGINE_VARS *ev;
        void A8GS_start();
        EVENT ShowKey(var _ScanCode);
        void buttonClicked(int, PANEL *);
        QWidget *A8GS_Widget_parent;
        bool A8GS_init_stop;
    
    signals:
    
    public slots:
        void engineStart();
        void engineClose();
        void engineBoxSign();
    };
    
    typedef void (*ButtonClickType)(int, PANEL *);
    ButtonClickType pointerToFunction = &A8GS_Widget::buttonClicked;
    

    Important part 1 from the cpp file, the function definition:

    void A8GS_Widget::buttonClicked(int buttonId, PANEL *panelId) {
        qDebug() << "buttonClicked";
        qDebug() << buttonId;
    }
    

    Important part 2 from the cpp file, where i want to pass the function as parameter:

    void A8GS_Widget::A8GS_start() {
    ...
        pan_setbutton(pan_ize, 0, 0, 104, 226, bmap_1, bmap_1, bmap_1, NULL, (void *)(&A8GS_Widget::buttonClicked), NULL, NULL);
    ...
    

    I hope i didn't miss nothing.


  • Qt Champions 2016

    It won't work like this. Remember I wrote that static functions can be passed as global functions (C-like functions). Methods (like buttonClicked) have to be bound to an object, which is problematic in your case, because pan_setbutton expect a C-style function, not a class method.



  • @kshegunov said in Passing function pointer:

    It won't work like this. Remember I wrote that static functions can be passed as global functions (C-like functions). Methods (like buttonClicked) have to be bound to an object, which is problematic in your case, because pan_setbutton expect a C-style function, not a class method.

    OK, and how will work?
    If you can see any possible changes, let me share, and i can continue my work. I started to use this Qt tool since one month and i really, really like.
    I would appreciate any good proposal.
    Thanks in advance.


  • Qt Champions 2016

    There aren't really good solutions for that one, that's why I was reluctant to propose anything. Your best bet is to use a global pointer to pass the context. Something like this:

    class A8GS_Widget : public QWidget
    {
        Q_OBJECT
    
        // ...
        static void panSetButton(int, PANEL *);
    
    private:
        static A8GS_Widget * currentWidget;
    };   
    

    And then in the .cpp:

    A8GS_Widget * A8GS_Widget::currentWidget = Q_NULLPTR;
    
    void A8GS_Widget::panSetButton(int id, PANEL * panelId)
    {
        Q_ASSERT(currentWidget);
        currentWidget->buttonClicked(id, panelId)
    }
    
    void A8GS_Widget::A8GS_start()
    {
        // ...
        currentWidget = this;
        pan_setbutton(pan_ize, 0, 0, 104, 226, bmap_1, bmap_1, bmap_1, NULL, &A8GS_Widget::panSetButton, NULL, NULL);
        // ...
    }
    

    It's not ideal, but it's how this problem is treated most commonly.



  • Thank for your will to help.
    I feel myself lucky, because i started another way to solve the problem. It seems to me works.
    I have made the following changes:

    1. I added static prefix tag to the function declaration, because i forgot to that earlier
    2. I moved the following statement from the header to the cpp as the first line of the void A8GS_Widget::A8GS_start()
    ButtonClickType pointerToFunction = &A8GS_Widget::buttonClicked;
    
    1. I changed the definition here:
    void A8GS_Widget::buttonClicked(int buttonId, PANEL *panelId)
    

    from int buttonId, to var buttonId.
    And it works! I like it!
    Only one problem remained, i got 1024 as buttonId that should be 1. I think this is my deal with the engine.
    Thanks for the quick and kind help.
    I am investigate a bit more, and later i set to solved this topic.



  • @kshegunov Thank for the real quick and expert help.
    I am happy with that.


  • Qt Champions 2016

    I'm glad I was of help. Happy coding!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.