wxWidgets复合控件按钮绑定任意成员函数的编译错误解决
wxWidgets传递成员函数指针作为回调编译失败问题
问题描述
我要创建多个带滚动列表和按钮的复合对象,这些对象只有布局、尺寸和按钮回调函数不同——同一个按钮在不同对象里要调用不同的函数。于是我想在复合对象的构造函数里接收要绑定给按钮的函数,但加了传入绑定函数的代码后编译直接失败。
编译错误信息
stack2.cpp: In constructor ‘MainPanel::MainPanel(wxFrame*)’: stack2.cpp:106:94: error: no matching function for call to ‘MyAddRemoveList::MyAddRemoveList(MainPanel*, const char [12], const char [11], int, int, int, bool, void (MyAddRemoveList::*)(wxCommandEvent&))’ 106 | xLB_MULTIPLE | wxLB_HSCROLL | wxLB_NEEDED_SB, false, &MyAddRemoveList::OnAddToList); 1,68 Top stack2.cpp:61:1: note: candidate: ‘MyAddRemoveList::MyAddRemoveList(wxWindow*, const char*, const char*, int, int, long int, bool, func)’ 61 | MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name, | ^~~~~~~~~~~~~~~ stack2.cpp:62:79: note: no known conversion for argument 8 from ‘void (MyAddRemoveList::*)(wxCommandEvent&)’ to ‘func’ {aka ‘void (*)(wxCommandEvent&)’} 62 | const char *table_name, int w, int h, long style, bool do_extract, func fpt) : | ~~~~~^~~ stack2.cpp:41:7: note: candidate: ‘MyAddRemoveList::MyAddRemoveList(const MyAddRemoveList&)’ 41 | class MyAddRemoveList : public wxBoxSizer { | ^~~~~~~~~~~~~~~ stack2.cpp:41:7: note: candidate expects 1 argument, 8 provided stack2.cpp:41:7: note: candidate: ‘MyAddRemoveList::MyAddRemoveList(MyAddRemoveList&&)’ stack2.cpp:41:7: note: candidate expects 1 argument, 8 provided make: *** [stack2.make:94: stack2.o] Error 1
环境说明
- 代码已精简到最小版本(无绑定的版本能正常运行,加绑定后编译失败)
- POP OS 22.04
- wxWidgets 3.0
相关代码片段
函数指针定义
using func = void(*)(wxCommandEvent& event);
构造函数
MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name, const char *table_name, int w, int h, long style, bool do_extract, func fpt) : wxBoxSizer(wxVERTICAL) { /* 其他代码 */
绑定尝试
/* 其他代码 */ wxButton *add = new wxButton(panel, wxID_ADD, "+", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); add->Bind( wxEVT_BUTTON, fpt );
构造函数调用
lookup_lists[0] = new MyAddRemoveList(this, "Ingredients", "ingredient", 80, 200, wxLB_MULTIPLE | wxLB_HSCROLL | wxLB_NEEDED_SB, false, &MyAddRemoveList::OnAddToList);
核心疑问
我搞不懂编译器为什么不能把void (MyAddRemoveList::*)(wxCommandEvent&)转换成void (*)(wxCommandEvent&),求解决办法。
解决办法
首先要明确:成员函数指针和普通函数指针是完全不同的类型,不能直接转换。普通函数指针只需要知道函数地址,而成员函数指针必须关联具体的对象实例才能调用——因为成员函数默认会接收一个this指针作为隐式参数,这是普通函数没有的。
针对wxWidgets的场景,推荐以下几种解决方案:
方案1:用lambda表达式直接绑定(最简洁)
不需要定义func类型,直接在绑定按钮时用lambda捕获当前对象实例,调用成员函数:
// 修改构造函数,去掉func参数 MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name, const char *table_name, int w, int h, long style, bool do_extract) : wxBoxSizer(wxVERTICAL) { // ...其他代码 wxButton *add = new wxButton(panel, wxID_ADD, "+", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); // lambda捕获this,调用成员函数 add->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { this->OnAddToList(evt); }); }
对应的构造函数调用简化为:
lookup_lists[0] = new MyAddRemoveList(this, "Ingredients", "ingredient", 80, 200, wxLB_MULTIPLE | wxLB_HSCROLL | wxLB_NEEDED_SB, false);
方案2:使用成员函数指针+std::bind(支持传入不同成员函数)
如果需要让构造函数支持传入不同的成员函数,可以定义成员函数指针类型,并用std::bind绑定对象实例:
// 先定义成员函数指针类型 using MemFunc = void (MyAddRemoveList::*)(wxCommandEvent&); // 修改构造函数参数为MemFunc MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name, const char *table_name, int w, int h, long style, bool do_extract, MemFunc func) : wxBoxSizer(wxVERTICAL) { // ...其他代码 wxButton *add = new wxButton(panel, wxID_ADD, "+", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); // 用std::bind绑定this和成员函数 add->Bind(wxEVT_BUTTON, std::bind(func, this, std::placeholders::_1)); }
构造函数调用保持原来的写法即可:
lookup_lists[0] = new MyAddRemoveList(this, "Ingredients", "ingredient", 80, 200, wxLB_MULTIPLE | wxLB_HSCROLL | wxLB_NEEDED_SB, false, &MyAddRemoveList::OnAddToList);
注意:需要包含<functional>头文件才能使用std::bind。
方案3:使用wxWidgets原生成员绑定语法(官方推荐)
wxWidgets本身支持直接绑定成员函数,不需要额外处理指针转换,写法非常简洁:
// 构造函数里不需要接收func参数 add->Bind(wxEVT_BUTTON, &MyAddRemoveList::OnAddToList, this);
这种方式类型安全,是wxWidgets官方推荐的绑定成员函数的方式。
不推荐方案:改成静态成员函数
如果硬要用普通函数指针,可以把OnAddToList改成静态成员函数,但这样无法访问对象的非静态成员变量,除非额外传递对象指针,灵活性极差,不建议使用。
内容的提问来源于stack exchange,提问作者Steve Quinn
相关产品推荐
相关产品推荐

