c++classpointer-to-membermember-pointers

How to pass pointer to a member within class to outer class?


I am trying to pass a pointer to memeber of class(Dialog::handler) from its method(in scope of Dialog::render) to some outer method(Button::OnClick).

Here is a small example:

        class Button
        {
        public:
            void OnClick(void (*handler)())
            {
                handler();
            }
        };

        class Dialog
        {
        public:
            void handler()
            {
                //do stuff
            }
            void render()
            {
                auto button = new Button;
                //Source of problem
                button->OnClick(this->*handler);
            }
        };

But compiler shows error:

non-standard syntax; use '&' to create a pointer to member

Also I triend other combinations, like:

But obviously they failed.


Solution

  • You could use std::function and pass it a lambda in which you've caught this of the object you'd like to call back:

    #include <functional>
    #include <iostream>
    
    class Button {
    public:
        void OnClick(std::function<void()> handler) {
            handler();
        }
    };
    
    class Dialog {
    public:
        void handler() {
            std::cout << "Dialog::handler\n";
        }
        void render() {
            auto button = new Button;
            // a lambda catching "this" Dialog.
            button->OnClick([this] { this->handler(); });
            delete button;                               // you didn't delete your button
        }
    };
    
    int main() {
        Dialog d;
        d.render();
    }
    

    But it looks like you should probably inherit from a common base class that has a virtual void handler() so you can pass object pointers/references around instead. A rough idea:

    #include <iostream>
    
    class VisualBase {
    public:
        virtual void handler() = 0;
        virtual ~VisualBase() = 0;
    };
    
    VisualBase::~VisualBase() {}
    
    class Button : public VisualBase {
    public:
        void handler() override {}
    
        void OnClick(VisualBase* caller) {
            caller->handler(); 
        }
    };
    
    class Dialog : public VisualBase {
    public:
        void handler() override { 
            std::cout << "Dialog::handler\n"; 
        }
    
        void render() {
            Button button;
            button.OnClick(this);
        }
    };
    
    int main() {
        Dialog d;
        d.render();
    }