类成员函数作为回调函数/事件模型

在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;
};
时间: 2024-08-03 02:24:34

类成员函数作为回调函数/事件模型的相关文章

C++中类成员函数作为回调函数

注:与tr1::function对象结合使用,能获得更好的效果,详情见http://blog.csdn.net/this_capslock/article/details/38564719 回调函数是基于C编程的Windows SDK的技术,不是针对C++的,程序员可以将一个C函数直接作为回调函数,但是如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过. 普通的C++成员函数都隐含了一个传递函数作为参数,亦即“this”指针,C++通过传递一个指向自身的指针给其成员函数从

Java/Android中的函数调用&amp;回调函数&amp;自定义回调函数

在做Android自定义控件时遇到要自定义回调函数的问题,想想自己还暂时没有那么精深的技术,赶紧返过头回来再重新研究Java中回调函数的问题.然而不幸的是,网上太多杂乱的帖子和博客都是转来转去,而且都是那一篇"C中的回调函数.....指针.....java....",一点看不出来是自己的思路,估计都是哪哪哪抄来的!(呵呵,要么就是吐槽对了,要么就是我水平太烂读不懂还妄加评论)还有一些很不错的文章,我会在最后参考中加上链接,大家可以看看. 那么来开始我们的正题--什么是回调函数? 我们一

c语言(函数指针,回调函数)

//  main.m //  1-28随堂笔记 //讲师: 小辉 //笔者: 王学文 //  Created by lanouhn on 15/1/28. //  Copyright (c) 2015年 lanouhn. All rights reserved. // 函数指针, 回调函数 #import <Foundation/Foundation.h> struct student { char name[20]; float score; int age; }; typedef stru

钩子函数和回调函数的区别

一般认为,钩子函数就是回调函数的一种,其实还是有差异的,差异地方就是:触发的时机不同. 先说钩子函数: 钩子(Hook)概念源于Windows的消息处理机制,通过设置钩子,应用程序对所有消息事件进行拦截,然后执行钩子函数. let btn = document.getElementById("btn"); btn.onclick = () => { console.log("i'm a hook"); } 上面的例子,在按钮点击时候立即执行钩子函数.而看下面的

普通函数与回调函数的区别

普通函数与回调函数的区别:对普通函数的调用:调用程序发出对普通函数的调用后,程序执行立即转向被调用函数执行,直到被调用函数执行完毕后,再返回调用程序继续执行.从发出调用的程序的角度看,这个过程为“调用-->等待被调用函数执行完毕-->继续执行” 对回调函数调用:调用程序发出对回调函数的调用后,不等函数执行完毕,立即返回并继续执行.这样,调用程序执和被调用函数同时在执行.当被调函数执行完毕后,被调函数会反过来调用某个事先指定函数,以通知调用程序:函数调用结束.这个过程称为回调(Callback)

新手,对函数,函数指针,回调函数, 函数指针作为函数的返回值和block的一些见解

很多初学者,学c语言时,看到函数都觉得难,我也是,一开始觉得函数太难了,后来慢慢就理解了 第一:函数 在c语言中最简单的函数一般有四种: 1, 无返回值, 无参数. 2, 无返回值,有参数. 3, 有返回值,无参数. 4, 有返回值,有参数 1, 无返无参  定义方式:      void 函数名(); 一般不怎么用这种形式的函数,可用来输出,打印 void functionOne() { printf("无返回值,无参数"); // 没有返回值不能写return } int main

什么是回调函数?回调函数适合在什么情况下使用?

一直不太理解回调函数的作用,下面是找到的一些关于回调函数的作用的解答. 1.回调函数是一个很有用,也很重要的概念.当发生某种事件时,系统或其他函数将会自动调用你定义的一段函数. 2.回调函数就相当于一个中断处理函数,由系统在符合你设定的条件时自动调用.为此,你需要做三件事:1,声明:2,定义:3,设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于系统调用. 3.所谓回调函数就是按照一定的形式由你定义并编写实现内容,当发生某种事件时,而由系统或其它函数来调用的函数.使用

【笔记】关于jq $.ajax 函数 success回调函数不能赋正确值或返回正确值的问题

最近在一个项目里面打算实现如下功能: 当我注册账号的时候当输入账号完毕后输入框失焦时执行一个 ajax 请求,验证账号是否被注册,并未这个输入框的 isCorrect属性赋值,如果没有被注册 isCorrect属性值为"true",否则为 "false".代码如下: ajax: function(obj){ /* { elem: //验证的元素, hintsContent: //提示框元素, errorColor: //错误时显示的颜色, url: //后台处理页地

JavaScript匿名函数和回调函数

格式: (function(){ //代码 })(); 函数表达式可以存储在变量中,变量也可以作为一个函数使用 可以将匿名函数作为参数传递给其它函数,接收方函数就可以通过所传递进来的函数完成某些功能 可以通过匿名函数来执行某些一次性的任务 <!doctype html> <html> <head> <meta charset="utf-8"/> <title></title> </head> <b