samedi 30 mai 2015

C++11 alternative to the Java anonymous callback class

I realise that the solution I have here is far from ideal with C++, so I'm asking what a proper C++ programmer would do in this situation. (C++11)

I have a DialogBox class, which stores a collection of buttons. At the moment I have a pure abstract inner class DialogBox::Button with the pure virtual function virtual void callback() const.

From Java I'm used to using this strategy to create and instantiate an anonymous class deriving from Button in-place which implements the callback function. Something like this:

db.add_button(new Button( "Button text", BUTTONTYPE ) {
    public void callback() {
        // Callback code
}});

which is what prompted this C++ solution.

My C++ solution therefore looks like

dialogbox.h

class DialogBox {
public:
    // Abstract class for buttons with callback functions
    class Button;

private:
    /* ...
      stuff 
     */

public:
    /* ...
      stuff 
     */
    const std::vector< unique_ptr<DialogBox::Button> >& get_buttons() const;
    void add_button( unique_ptr<DialogBox::Button>& new_button );
};


class DialogBox::Button {

private:
    /* ...
      stuff
     */

public:
    // Constructor
    Button( const string& button_text, const DialogButtonType button_type = DialogButtonType::NORMAL );

    /* ...
      stuff
     */

    // Virtual callback function
    virtual void callback() const = 0;

};

Usage:

// Instantiate
DialogBox db{ /* ... args ... */ };
// Test adding buttons
class Button1 : public DialogBox::Button {
    using DialogBox::Button::Button;
    public: void callback() const {
        // Callback code
    }
};
std::unique_ptr<DialogBox::Button> button1{ new Button1{ "Button1", DialogButtonType::ENTER } };
db.add_button( button1 );

This works, but it's clearly not as clean as the Java version and certainly feels like I'm shoehorning in something that C++ is not designed to do.

So, how would a C++ programmer do this? It seems conceptually right to have Button as a class (since it has internal data and its own behaviour). At the moment I'm thinking of using a lambda expression to pass in the callback function to Button's constructor, but I thought I'd get some expert opinion on the subject.

Aucun commentaire:

Enregistrer un commentaire