首页 > 代码库 > 类成员函数作为回调函数/事件模型
类成员函数作为回调函数/事件模型
在C++中,有需要将类的成员函数作为某一个组件/API的回调函数的需求,应对这种需求,可以使用:
1、C++ 11里面的 std::function 和 std::bind 代替回调函数;
class EventArgs { public: EventArgs(){} virtual ~EventArgs(){} }; typedef std::function<void(void* sender, EventArgs* args)> EventHandler;
class Wnd { public: Input::EventHandler Event_Init; void Dosth() { if (Event_Init) { EventArgs args; Event_Init(this, &args); } } }; class APP { public: APP() { m_wnd.Event_Init = EVENT_SLOT(&APP::OnEvent_Init); } ~APP(){} void OnEvent_Init(void* _sender, EventArgs* _args) { } Wnd m_wnd; };
如果是调用系统API之类的接口,就不能用这种方式了;
2、使用命令模式的变种:
class Event { public: Event(){} virtual ~Event(){} virtual void Invoke(void* _sender, EventArgs* _args) = 0; }; template <class Receiver> class EventSTD : public Event { public: //事件处理函数签名 typedef void (Receiver:: * Action)(void* _sender, EventArgs* _args); //构造器 EventSTD(Receiver* r, Action a) : _receiver(r), _action(a){} virtual void Invoke(void* _sender, EventArgs* _args) { (_receiver->*_action)(_sender, _args); } private: Action _action; Receiver* _receiver; };
应用:
class EventArgs_Btn : public EventArgs { public: EventArgs_Btn(){} ~EventArgs_Btn(){} public: int x; int y; bool IsPress; }; class ButtonEx { public: //所有事件都可以使用该模型定义(可以使用智能指针,隐藏释放过程) Event* Event_Init; ButtonEx() : Event_Init(nullptr){} ~ButtonEx() { //release delete Event_Init; Event_Init = nullptr; } void DoSth() { if (Event_Init == nullptr) return;//error EventArgs_Btn args; args.x = 10; args.y = 20; args.IsPress = false; Event_Init->Invoke(this, &args); if (args.IsPress) { //feedback ... cout << "btn press!" << endl; } } private: }; class Wnd { public: Wnd() { m_Btn.Event_Init = new EventSTD<Wnd>(this, &Wnd::Init); } ~Wnd() { } void Init(void* _sender, EventArgs* _args) { //use and convert sender; // auto pArgs = reinterpret_cast<EventArgs_Btn*>(_args); if (pArgs == nullptr){ //error handler return; } int x = pArgs->x; int y = pArgs->y; pArgs->IsPress = true; } void Proc() { m_Btn.DoSth(); } private: ButtonEx m_Btn; }; int _tmain(int argc, _TCHAR* argv[]) { Wnd wnd; wnd.Proc(); return 0; }
这种方式是借鉴了C#中的事件模型,所有的事件响应函数签名如下:
void OnEvent(void* _sender, EventArgs* _args)
事件的入参和出参都放在事件参数对象EventArgs里面,你可以派生生成不同的参数对象,如例子中的EventArgs_Btn;
这种签名可以实现一对多的订阅,即一个OnEvent函数可以订阅多个事件,然后通过sender来区分不同的触发源。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
附命令模型代码:
class Command { public: virtual ~Command(); virtual void Execute() = 0; virtual void UnExecute(); protected: Command(); }; template <class Receiver> class SimpleCommand : public Command { public: typedef void (Receiver:: * Action)(); SimpleCommand(Receiver* r, Action a) : _receiver(r), _action(a){} virtual void Execute(){ (_receiver->*_action)(); } private: Action _action; Receiver* _receiver; }; class Button { public: void Click() { _BtnClick->Execute(); } public: Command* _BtnClick; }; class Client { public: Client() { _btn._BtnClick = new SimpleCommand<Client>(this, &Client::OnBtnClick); } //Receiver void OnBtnClick() { cout<<"Client::OnBtnClick"<<endl; } void OnBtnClick2() { } public: Button _btn; };
类成员函数作为回调函数/事件模型
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。