我意识到我这里的解决方案对于 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 的构造函数,但我想我可以获得有关该主题的一些专家意见。
最佳答案
C++11 解决方案是让 Button
看起来像这样。为了简洁起见,我跳过了 string
和 DialogButtonType
参数:
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
参数。
关于java - Java 匿名回调类的 C++11 替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30545884/