在C++中模拟委托事件的方法(二)

下边来看具体的实现方案

 

一、静态函数模拟事件

对应的例子工程名StaticFunctionEvent

1、  具体的实现方法

(1)、事件触发对象类CNotifyClass的类定义如下:

typedef void (*PEVENT_NOPARAM_NORETURN)(void *);
typedef int (*PEVENT_NOPARAM_RETURN)(void *);
typedef void (*PEVENT_PARAM_NORETURN)(void *, int);
typedef int (*PEVENT_PARAM_RETURN)(void *, int);

class CNotifyClass
{
public:
	CNotifyClass(void);
	~CNotifyClass(void);

public:
	bool RegisterEvent(PEVENT_NOPARAM_NORETURN pFunc1, PEVENT_NOPARAM_RETURN pFunc2,
		PEVENT_PARAM_NORETURN pFunc3, PEVENT_PARAM_RETURN pFunc4, void *pParameter);
	void UnRegisterEvent();

	void DoNotifyEventWork();

protected:
	PEVENT_NOPARAM_NORETURN m_pNoParam_NoReturn_EventHandler;
	PEVENT_NOPARAM_RETURN m_pNoParam_Return_EventHandler;
	PEVENT_PARAM_NORETURN m_pParam_NoReturn_EventHandler;
	PEVENT_PARAM_RETURN m_pParam_Return_EventHandler;

protected:
	void *m_pEventParameter;
};

类实现如下:

#include "NotifyClass.h"

CNotifyClass::CNotifyClass(void)
	: m_pEventParameter(NULL)
	, m_pNoParam_NoReturn_EventHandler(NULL)
	, m_pNoParam_Return_EventHandler(NULL)
	, m_pParam_NoReturn_EventHandler(NULL)
	, m_pParam_Return_EventHandler(NULL)
{
}

CNotifyClass::~CNotifyClass(void)
{
	UnRegisterEvent();
}

bool
CNotifyClass::RegisterEvent(PEVENT_NOPARAM_NORETURN pFunc1, PEVENT_NOPARAM_RETURN pFunc2,
	PEVENT_PARAM_NORETURN pFunc3, PEVENT_PARAM_RETURN pFunc4, void *pParameter)
{
	if (NULL != m_pNoParam_NoReturn_EventHandler)
		return false;
	m_pEventParameter = pParameter;
	m_pNoParam_NoReturn_EventHandler = pFunc1;
	m_pNoParam_Return_EventHandler = pFunc2;
	m_pParam_NoReturn_EventHandler = pFunc3;
	m_pParam_Return_EventHandler = pFunc4;
	return true;
}

void
CNotifyClass::UnRegisterEvent()
{
	m_pEventParameter = NULL;
	m_pNoParam_NoReturn_EventHandler = NULL;
	m_pNoParam_Return_EventHandler = NULL;
	m_pParam_NoReturn_EventHandler = NULL;
	m_pParam_Return_EventHandler = NULL;
}

void
CNotifyClass::DoNotifyEventWork()
{
	int iResult = 0;
	if (m_pNoParam_NoReturn_EventHandler != NULL)
		m_pNoParam_NoReturn_EventHandler(m_pEventParameter);
	if (m_pNoParam_Return_EventHandler != NULL)
		iResult = m_pNoParam_Return_EventHandler(m_pEventParameter);

	iResult = iResult + 10;
	if (m_pParam_Return_EventHandler != NULL)
		iResult = m_pParam_Return_EventHandler(m_pEventParameter, iResult);
	iResult = iResult + 10;
	if (m_pParam_NoReturn_EventHandler != NULL)
		m_pParam_NoReturn_EventHandler(m_pEventParameter, iResult);
}

类CNotifyClass声明时要提供类似如下的事件处理函数声明,所有接收事件的对象都要使用如下的函数声明来定义函数

typedef void (*PEVENT_NOPARAM_NORETURN)(void*);

事件接收对象类通过调用RegisterEvent和UnRegisterEvent注册接收消息或取消注册不再接收消息,当会触发消息的工作方法DoNotifyEventWork被调用时,会检测哪些事件被注册了,被注册了就调用,就如同进行了事件通知。


(2)、事件接收对象类或事件处理对象类CRecvEventClass的类定义如下:

class CRecvEventClass
{
public:
	CRecvEventClass(void);
	~CRecvEventClass(void);

public:
	int DoWork(int iArg);

protected:
	static void OnNoParamNoReturnEvent(void *pvParam);
	static int OnNoParamReturnEvent(void *pvParam);
	static void OnParamNoReturnEvent(void *pvParam, int iArg);
	static int OnParamReturnEvent(void *pvParam, int iArg);

protected:
	CNotifyClass m_ncNotify;
	int m_nNum;
};

类实现如下:

#include "RecvEventClass.h"

CRecvEventClass::CRecvEventClass(void)
{
	m_ncNotify.RegisterEvent(OnNoParamNoReturnEvent, OnNoParamReturnEvent, OnParamNoReturnEvent, OnParamReturnEvent, this);
}

CRecvEventClass::~CRecvEventClass(void)
{
	m_ncNotify.UnRegisterEvent();
}

int
CRecvEventClass::DoWork(int iArg)
{
	m_nNum = iArg;
	m_ncNotify.DoNotifyEventWork();
	return m_nNum;
}

void
CRecvEventClass::OnNoParamNoReturnEvent(void *pvParam)
{
	_tprintf(_T("Run OnNoParamNoReturnEvent\n"));
	if (pvParam != NULL)
	{
		CRecvEventClass *p = reinterpret_cast<CRecvEventClass *>(pvParam);
		p->m_nNum = p->m_nNum + 10;
	}
}

int
CRecvEventClass::OnNoParamReturnEvent(void *pvParam)
{
	_tprintf(_T("Run OnNoParamReturnEvent\n"));
	if (pvParam != NULL)
	{
		CRecvEventClass *p = reinterpret_cast<CRecvEventClass *>(pvParam);
		p->m_nNum = p->m_nNum + 10;
		return p->m_nNum;
	}
	else
		return 0;
}

void
CRecvEventClass::OnParamNoReturnEvent(void *pvParam, int iArg)
{
	_tprintf(_T("Run OnParamNoReturnEvent\n"));
	if (pvParam != NULL)
	{
		CRecvEventClass *p = reinterpret_cast<CRecvEventClass *>(pvParam);
		p->m_nNum = iArg + 10;
	}
}

int
CRecvEventClass::OnParamReturnEvent(void *pvParam, int iArg)
{
	_tprintf(_T("Run OnParamReturnEvent\n"));
	int iRet = iArg + 10;
	return iRet;
}

这里事件接收对象类或事件处理对象类CRecvEventClass在定义时一定要定义同事件触发类CNotifyClass提供的方法声明相同的方法来接收处理事件,由于CNotifyClass定义的方法声明是普通的指向函数指针,不包含对象的this指针传递,所以这种方法不能是实例成员函数,只能是静态成员方法,就如同

static void OnNoParamNoReturnEvent(void *pvParam);

当定义了事件处理方法后,可以通过调用类CNotifyClass的方法RegisterEvent和UnRegisterEvent注册接收消息或取消注册不再接收消息,本例是在构造和析构函数中调用的,当CNotifyClass类的DoNotifyEventWork方法被调用时,就会通过函数指针事件通知到类CRecvEventClass,在事件处理方法中为了能区分CRecvEventClass的不同实例,所以要在类CNotifyClass的方法RegisterEvent中提供了pParameter参数,通常CRecvEventClass在调用RegisterEvent时传递对象本身的this指针,这样在事件处理方法中就可以通过pvParam参数得到这个指针的类实例的this指针,就像OnNoParamNoReturnEvent中的代码

CRecvEventClass::OnNoParamNoReturnEvent(void *pvParam)
{
	_tprintf(_T("Run OnNoParamNoReturnEvent\n"));
	if (pvParam != NULL)
	{
		CRecvEventClass *p = reinterpret_cast<CRecvEventClass *>(pvParam);
		p->m_nNum = p->m_nNum + 10;
	}
}

可以直接将pvParam参数转化为CRecvEventClass类实例的指针,然后就像成员方法一样访问类实例的其他方法和成员了。

(3)、使用的例子及输出

int _tmain(int argc, _TCHAR* argv[])
{
	//2个对象,虽然类里用的静态方法,但是不会影响到不同对象的调用,互相不会干扰其他的对象的状态
	CRecvEventClass rec1, rec2;
	int iIn, iOut;

	iIn = 10;
	iOut = rec1.DoWork(iIn);
	_tprintf(_T("StaticFunctionEvent test 1, Init:%d, Result:%d\n"), iIn, iOut);
	iIn = 30;
	iOut = rec1.DoWork(iIn);
	_tprintf(_T("StaticFunctionEvent test 2, Init:%d, Result:%d\n"), iIn, iOut);
	iIn = 60;
	iOut = rec2.DoWork(iIn);
	_tprintf(_T("StaticFunctionEvent test 3, Init:%d, Result:%d\n"), iIn, iOut);

	TCHAR c;
	_tscanf(_T("%c"), &c);
	return 0;
}

输出结果为:

Run OnNoParamNoReturnEvent
Run OnNoParamReturnEvent
Run OnParamReturnEvent
Run OnParamNoReturnEvent
StaticFunctionEvent test 1, Init:10, Result:70
Run OnNoParamNoReturnEvent
Run OnNoParamReturnEvent
Run OnParamReturnEvent
Run OnParamNoReturnEvent
StaticFunctionEvent test 2, Init:30, Result:90
Run OnNoParamNoReturnEvent
Run OnNoParamReturnEvent
Run OnParamReturnEvent
Run OnParamNoReturnEvent
StaticFunctionEvent test 3, Init:60, Result:120

从输出结果上看事件是被顺次调用了,至于程序中的变量值,主要表明这些事件执行的而动作是对应于实例的,不是因为是静态方法就是对应于类的。

2、  实现的要点

 (1)、事件触发类的实现要点

a、  事件触发类必须要定义要处理事件的函数声明

b、  事件触发类要定义相应函数声明类型的成员变量

PEVENT_NOPARAM_NORETURN m_pNoParam_NoReturn_EventHandler;

c、  为了能传递事件接收类的实例,要定义事件接收类的实例指针

void *m_pEventParameter;

d、  或者把上面的函数指针成员和事件接收类的实例指针直接公开被外部修改,或者使用类似RegisterEvent和UnRegisterEvent的方法提供对这些成员的修改,外部事件接收类才能接收事件

e、  在工作时,需要触发事件的地方,通过调用函数指针成员来事件通知事件接收类

(2)、事件接收对象类或事件处理对象类的实现要点

a、  使用静态方法定义与实现满足事件接收函数声明的方法

b、  使用这些静态方法及自身作为参数调用事件触发类的RegisterEvent和UnRegisterEvent的方法,或者直接修改事件触发类的相应成员(如果提供了访问权限)

c、  在这些静态方法中,转换参数为this,然后进行工作,当有事件触发时就可以得到通知被调用。

3、  优缺点

(1)、优点

a、可以部分接收事件,如果不接收什么事件,只需要在调用RegisterEvent时传递NULL给对应的事件函数就可以

b、事件处理方法不需要必须是public的方法,任意访问类别都可以

(2)、缺点

类型安全度相对较底,需要类型转换,不容易在编译期间发现问题,这里主要是指传递的参数pParameter,对于事件处理函数的指针是类型安全的

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值