C++委托的实现

24 篇文章 0 订阅
24 篇文章 0 订阅
 
GameRes开发文档
 


模版函数指针,C++委托的实现-原创【申请加精】


今天写引擎的时候,很想加入一些回调函数,以前一直没时间整理这块,这次一定要下决心好好整整代码,纯粹用多态,很多类非要加个帽子,类之间的关系也显的很单一,有的情况需要用到委托的回调机制,这是个很好的东西,在C#里面是原生支持的,C++里面本来函数指针是个不错的选择,可到了对象里面,成员函数指针还有那么好用吗?这原本是另C++程序员非常失望和无赖的,难道一说到成员函数指针就真的那么不好用,甚至要沦为被唾弃的命运?并非入此,别忘了,C++里面还有很强的利器,C#和Java后天才具备的特性可是C++先天就具备的哦,那就是范型,C++里面的用的是模版,而且如果把 模版和成员函数指针结合在一起,那就威力无比了,那应该叫做就是“成员模版函数指针”,C++的教科书上有这个名词吗?我查了查,好像是没有,而且网上很多资料竟然说这个不能实现之类的话,我都怀疑那些如此断言的人是否太不负责仁了,误导人啊。

当然指想成员函数的指针,这里面的确有段C++设计的问题,C++的成员函数地址通过对象外去引用不能直接通过“&对象.方法”的方式来引用,这个在C++标准里面是没有的,很多人到这里就绝望了,可间接引用呢?而且用很优雅的方式来引用呢?

好了,我也不绕圈子了,给出我的代码,一个简单的 “成员模版函数指针” 的实现,看看C++是如何优雅的实现委托的,真的非常非常的优雅,由于完全自己摸索出来的,真是感慨万千啊。

#include "stdafx.h"

#include <iostream>

using namespace std;

template<typename T>
class A
{
private:
   typedef int (T::*delegateFun)(int);
   T * _This;
   delegateFun _deleGate;

public:    

 //This被代理的对象, delegateFun被代理的方法
 
 A(T * This, int (T::*delegateFun)(int))
 { 
       _This = This;
       _deleGate = delegateFun;
 }

    //c被代理的参数
 int execue(int c)
 {
      return (_This->*_deleGate)(c);
 }

};


class B
{
public:
 int FunA(int a) {return a + 10;}
 int FunB(int a) {return a - 10;}
 B()
 {

 }
};

int _tmain(int argc, _TCHAR* argv[])
{


 B *objB = new B();

 A<B>  delegateObj1(objB, (&B::FunA));
 A<B>  delegateObj2(objB, (&B::FunB));


 cout << delegateObj1.execue(10) <<endl;
 cout << delegateObj2.execue(20) <<endl;

 return 0;

}

 

 

 

看完了感觉如何?以后想要设计一个callback回调函数是否明朗了许多?
再也不需要强行搞个static约束方法,那么恶心的东西了吧


原文出处
http://www.cppblog.com/tonykee/archive/2008/09/29/63034.html

资讯仅供参考,不代表本站(GameRes.com)观点,此信息由tonykee提交。 

发布日期:2008-9-29 16:11:00

去发表看法



网友回复:

tonykee在网上搜索了一下,有更好的实现
那就是: FastDelegate

bskk很实用,支持!!!

justlikethewind我一直用boost的function的,虽然笨重了点,不过还行。

instemast几年前我就开始更新过N多版本。不仅有delegate,还有non-blocking event。(用队列实现)
以及,处理了引用安全。

instemastcallback的核心代码是这个:

class __obj{};

#undef INST_THISCALLBACK
#define INST_THISCALLBACK(pthis,pfunc,rettype,params,args)  ( reinterpret_cast<__obj *>(pthis) ->* ::inst::union_cast<rettype (__obj:: *)params>(pfunc) ) args

但是在 instEvent.h 中有保存了多个handler的Event对象和实现非阻塞事件的队列


instemast奉劝LZ写引擎的时候,不要单纯用delegate----如果你不想毁掉你的引擎的话。

delegate应该放入queue中,用户可以在稍后进行peek.

比如:

MyEvent.PostEvent( this, new CMyEventArgs() );

在类库处理全部完成后,用户才可以调用:

CEvengMgr::PeekAll(); // callback所有动态成员函数。

还有,对于属性值不要用 PropXxxChanged 这样的event,而要用Update去刷新。
(因为是Game而不是Soft编程)


instemast//instEvent.h
#ifndef INST_EVENT_H
#define INST_EVENT_H


#include <instDefines.h>
#include <instArray.h>
#include <instList.h>


namespace inst
{


template <typename T> val_class _EventMgr // 必须用用SmartPtr保持强引用,而Peek()之后引用就会解除引用
{
public:
typedef void (__obj:: *EVENTFUNC)(IDynamic *,const void *);
typedef struct _EVENTCALL
{
void *pObjAddr; // thiscallのために用いられる。
SmartPtr<IDynamic> pObjRoot; // 参照回数計測のために用いられる。Peek()之后引用就会解除
SmartPtr<IDynamic> pSender; // Peek()之后引用就会解除
EVENTFUNC pFunc;
const void *pArgsAddr;
SmartPtr<const IDynamic> pArgsRoot;

Bool operator ==(const _EVENTCALL &o)
{
return pObjAddr==o.pObjAddr && pObjRoot==o.pObjRoot && pSender==o.pSender &&
pFunc==o.pFunc && pArgsAddr==o.pArgsAddr && pArgsRoot==o.pArgsRoot;
}
Bool operator !=(const _EVENTCALL &o)
{
return pObjAddr!=o.pObjAddr || pObjRoot!=o.pObjRoot || pSender!=o.pSender ||
pFunc!=o.pFunc || pArgsAddr!=o.pArgsAddr || pArgsRoot!=o.pArgsRoot;
}

}EVENTCALL;

private:
static List<EVENTCALL> s_EventCalls;
static Int32 s_MaxSize;

public:
static void Post(const EVENTCALL &ec)
{
INST_ASSERT(ec.pObjAddr);
INST_ASSERT(ec.pObjRoot);
INST_ASSERT(ec.pSender);
INST_ASSERT(ec.pFunc);
INST_ASSERT(ec.pArgsAddr);
INST_ASSERT(ec.pArgsRoot);

s_EventCalls.Add(ec); // Peek()之后强引用们就会解除
if( s_MaxSize>0 && s_EventCalls.Count()>s_MaxSize ) s_EventCalls.Remove(0);
}
public:
static Bool Peek()
{
if(s_EventCalls.Count()==0) return False;

EVENTCALL ec = s_EventCalls.GetRemove(0);

INST_ASSERT(ec.pObjAddr);
INST_ASSERT(ec.pObjRoot);
INST_ASSERT(ec.pSender);
INST_ASSERT(ec.pFunc);
INST_ASSERT(ec.pArgsAddr);
INST_ASSERT(ec.pArgsRoot);

INST_THISCALLBACK(ec.pObjAddr, ec.pFunc, void, (const IDynamic *,const void *), (ec.pSender,ec.pArgsAddr));
return True;
}
static void PeekAll()
{
while(Peek()){};
}
static void SetMaxSize(Int32 maxsize){ s_MaxSize = MAX(maxsize,1); } // 最小为1
};

typedef _EventMgr<void> CEventMgr;

#if _MSC_VER<1400

template <class T> List<_EventMgr<T>::EVENTCALL> _EventMgr<T>::s_EventCalls;
template <class T> Int32 _EventMgr<T>::s_MaxSize = 0; // 0 - no limit

#else

List<CEventMgr::EVENTCALL> CEventMgr::s_EventCalls;
Int32 CEventMgr::s_MaxSize = 0; // 0 - no limit

#endif


template <class A> val_class Event
{
private:
typedef struct _EVENTHANDLER
{
void *pObjAddr;
IDynamic *pObjRoot; // 这里是weak ptr!这里的IDynamic不是用来增加RefCount的,而是等到RaiseEvent的时候传给EventMgr(他要增加RefCount)。 注意,不用了的话,应当RemoveHandler.
CEventMgr::EVENTFUNC pFunc; // ...某个FormXXX在destructing的时候,只允许RemoveHandler(自己的),因为控件和他的Handler可能正在别处被使用

Bool operator ==(const _EVENTHANDLER &o)const{ return pObjAddr==o.pObjAddr && pObjRoot==o.pObjRoot && pFunc==o.pFunc; }
Bool operator !=(const _EVENTHANDLER &o)const{ return pObjAddr!=o.pObjAddr || pObjRoot!=o.pObjRoot || pFunc!=o.pFunc; }

}EVENTHANDLER;

Array<EVENTHANDLER> m_EventHandlers;

public:
Event():m_EventHandlers(){}

#if _MSC_VER < 1400
template <class O,class F> void AddHandler(O *obj,F func)
#else
template <class O> void AddHandler(O *obj,void (O:: *func)(IDynamic *,const A *))
#endif
{
INST_ASSERT(obj);
INST_ASSERT(func);

EVENTHANDLER eh;
eh.pObjAddr = reinterpret_cast<void *>(obj);
eh.pObjRoot = static_cast<IDynamic *>(obj);
eh.pFunc = union_cast<CEventMgr::EVENTFUNC>(func);

if(m_EventHandlers.Find(eh))return;
m_EventHandlers.Add(eh);
}

#if _MSC_VER < 1400
template <class O,class F> void RemoveHandler(O *obj,F func)
#else
template <class O> void RemoveHandler(O *obj,void (O:: *func)(IDynamic *,const A *))
#endif
{
INST_ASSERT(obj);
INST_ASSERT(func);

EVENTHANDLER eh;
eh.pObjAddr = reinterpret_cast<void *>(obj);
eh.pObjRoot = obj; // 自动转换为 SmartPtr<IDynamic *> 为安全绝不可以写强制转换!
eh.pFunc = union_cast<CEventMgr::EVENTFUNC>(func);

m_EventHandlers.FindRemove(eh);
}

void PostEvent(IDynamic *sender,const A *args) // 允许用户直接传入 new Args~~用户没必要AddRef/Release~~
{
INST_ASSERT(sender);
INST_ASSERT(args);

CEventMgr::EVENTCALL ec;
ec.pSender = sender; // SmartPtr,但是,这里是Stack,绝对不会发生自引用或循环引用!
ec.pArgsAddr = reinterpret_cast<const void *>(args);
ec.pArgsRoot = static_cast<const IDynamic *>(args);

// 必须要对这些强引用AddRef/Release。否则,如果用户是直接new的话,那么永远不会被删除...
if(m_EventHandlers.Count()==0) return; // ...上面的ec.pArgsRoot是SmartPtr,所以这里可以直接安全return

EVENTHANDLER eh;
for(Int32 i=0; i<m_EventHandlers.Count(); i++)
{
eh=m_EventHandlers.Get(i);

ec.pObjAddr = eh.pObjAddr;
ec.pObjRoot = eh.pObjRoot;
ec.pFunc = eh.pFunc;

CEventMgr::Post(ec); // RefCount of Args and Obj, will be added here
}

}
};


class CNullEventArgs:virtual public IDynamic
{
INST_DYNAMIC1(L"inst.CNullEventArgs");
protected:
~CNullEventArgs(){}
};

typedef Event<CNullEventArgs> CSimpleEvent;

class CGlobalEventSender:virtual public IDynamic // 按要求sender不能为null,所以全局Event用这个类的实例
{
INST_DYNAMIC1(L"inst.CGlobalEventSender");
protected:
~CGlobalEventSender(){}
};

// a sample:
//void Form_MouseDown(IDynamic *sender, const CMouseEventArgs *e);


}//end of namespace inst


#endif


 

查看更多回复

 
 
 


关于本站 | 投稿指南 | 广告服务 | 联系本站

未经书面许可,请勿转载、链接本站内容,否则非法引用所造成的后果自负;
本站不对所提供的所有资讯正确性负责,若因资讯导致的任何损失本站概不负责,请自行斟酌。
闽ICP备05005107号
Copyright © 2001-2008 GameRes游戏开发资源网 All Rights Reserved.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值