C ++ 11替代Java匿名回调类

时间:2015-05-30 11:59:17

标签: java c++ c++11 callback abstract-class

我意识到我在这里的解决方案远非理想的C ++,所以我问的是一个合适的C ++程序员在这种情况下会做什么。 (C ++ 11)

我有一个DialogBox类,它存储了一组按钮。目前,我有一个纯粹的抽象内部类DialogBox::Button,其中包含纯虚函数virtual void callback() const

从Java我习惯使用这个策略来创建和实例化一个从Button就地派生的匿名类,它实现了回调函数。像这样:

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

这促使了这个C ++解决方案。

因此,我的C ++解决方案看起来像

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;

};

用法:

// 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 );

这很有效,但它显然不像Java版本那么干净,当然我感觉自己就像C ++不想做的那样。

那么,C ++程序员将如何做到这一点?将Button作为一个类在概念上似乎是正确的(因为它有内部数据和它自己的行为)。目前我正在考虑使用lambda表达式将回调函数传递给Button的构造函数,但我想我会就这个问题得到一些专家意见。

2 个答案:

答案 0 :(得分:3)

C ++ 11解决方案是让Button看起来像这样。为简洁起见,我正在跳过stringDialogButtonType参数:

class Button {
public:
    template <typename F>
    Button(F&& f) : cb(std::forward<F>(f))
    { }

    void callback() { cb(); }

private:
    std::function<void()> cb; // type-erased functor for ANY callable
                              // that takes zero arguments
};

这允许你有一个Button的容器,它们在callback中完全可以完成任意事情 - 不需要继承。它还允许您通过在构造过程中为其提供任意回调函数来实现一个很好的一次性按钮:

db.add_button(std::make_unique<Button>([=]{
     // arbitrary Callback code
}));

作为旁注,add_button绝对应该按值unique_ptr参数,而不是参考。

答案 1 :(得分:0)

考虑聚合:

{'Salary': ('9,00,000', '3,00,000', '1,01,00,000', '55,00,000'), 'Player': ('Acevedo, Juan', 'Anderson, Jason', 'Clemens, Roger', 'Contreras, Jose'), 'Position': ('Pitcher', 'Pitcher', 'Pitcher', 'Pitcher'), 'Team': ('New York Yankees', 'New York Yankees', 'New York Yankees', 'New York Yankees')}
('9,00,000', '3,00,000', '1,01,00,000', '55,00,000')

现在你可以struct Button { std::string name; std::function<void()> on_click; };

最小代码,最小样板。

我通常从这种事情开始,只根据需要添加更多基础设施。