原则上,指向成员的指针没有错。
例如,请参见以下代码:
#include <iostream>
/** Some API */
struct Button {
virtual void OnClick() = 0;
};
struct BaseMenu {
void f1(Button* b) {
std::cout << "f1(Button*)\n";
b->OnClick();
}
void f2(Button* b) {
std::cout << "f2(Button*)\n";
b->OnClick();
}
void Update() {
}
};
typedef void(BaseMenu::*ClickAreaCallback)(Button*);
struct Message{
ClickAreaCallback func;
Button* clickArea;
BaseMenu* funObj;
};
/** Usage */
class OKButton : public Button {
void OnClick() {
std::cout << "OKButton::OnClick()\n";
}
};
int main(int nArg, char* args[]) {
// Fill message:
BaseMenu menu;
OKButton ok;
Message m1, m2;
m1.func = &BaseMenu::f1;
m1.funObj = &menu;
m1.clickArea = dynamic_cast<Button*>(&ok);
m2.func = &BaseMenu::f2;
m2.funObj = &menu;
m2.clickArea = dynamic_cast<Button*>(&ok);
(m1.funObj ->* m1.func)(m1.clickArea);
(m2.funObj ->* m2.func)(m2.clickArea);
}
但这看起来像是一个概念性错误。你不应该需要回调。按钮应该从基类派生并具有执行特定操作的虚拟成员函数。
下面的示例演示了继承而不是回调的用法。
请注意,ButtonToggle 是在按钮内部存储信息的示例,而 ButtonNotify 是按钮通知菜单的示例。
#include <iostream>
#include <vector>
/** Some API */
struct Button {
double _area[4]; // rectangle x1,y1,x2,y2
Button(std::initializer_list<double> area) {
std::copy(area.begin(),area.begin()+4,_area);
}
virtual void OnClick() = 0;
};
class BaseMenu {
protected:
std::vector<Button*> _buttons;
public:
void Register(Button* btn) {
_buttons.push_back(btn);
}
void OnClick(double pt[2]) {
for(auto iBtn = _buttons.begin(); iBtn!=_buttons.end(); iBtn++) {
if( (*iBtn)->_area[0] <= pt[0] && pt[0] <= (*iBtn)->_area[2]
&& (*iBtn)->_area[1] <= pt[1] && pt[1] <= (*iBtn)->_area[3] ) {
(*iBtn)->OnClick();
}
}
}
};
struct MyMenu : public BaseMenu {
struct ButtonToggle: public Button {
bool _val;
ButtonToggle() :
Button( {0.0,0.0,1.0,1.0} )
{
_val = false;
}
void OnClick()
{
std::cout << "ButtonToggle::OnClick()\n";
_val = not(_val);
}
} buttonToggle;
void DoSomething() {
std::cout << "DoSomething()\n";
}
struct ButtonNotify: public Button {
MyMenu& _myMenu;
ButtonNotify(MyMenu& myMenu) :
Button( {2.0,0.0,3.0,1.0} ),
_myMenu(myMenu)
{}
void OnClick() {
_myMenu.DoSomething();
}
} buttonNotify;
MyMenu() :
buttonNotify(*this)
{
Register(&buttonToggle);
Register(&buttonNotify);
}
};
int main(int nArg, char* args[]) {
MyMenu menu;
double pt[2];
while(( std::cout << "\nCoordinates (end: -1 -1):",
std::cin >> pt[0] >> pt[1],
not( pt[0] == -1.0 and pt[1] == -1.0 ) )) {
menu.OnClick(pt);
}
}
/*
Local Variables:
compile-command: "g++ -g -std=c++11 test1.cc"
End:
*/