委托的核心就是封装类成员函数,使不同类的不同函数能够以一种统一的方式被调用
这样进行回调的方式要比使用接口通知模型少写很多代码,避免了重复工作
如果不使用c++11的新特性当然也能自己抡一个类似的轮子(而且还可以随意拓展)
不过有现成没有理由不用
function:函数对象,可以认为这个对应于c#中的委托,不过c++11没有提供事件的抽象,下面就要实现它
bind:创建函数对象的工具
下面的一个类实现了类似c#事件(在c++里面还是叫委托好了)的模板
struct __ut_delegate_id
{
template<typename T>
friend class ut_delegate;
private:
static int64 s_delageteID;
static int64 getID()
{
return s_delageteID++;
}
};
template<typename T>
class ut_delegate
{
private:
map<int64,T> m_listeners;
static int s_Serial;
public:
int64 add(T func)
{
int64 id=__ut_delegate_id::getID();
m_listeners.insert(pair<int64,T>( id,func));
return id;
}
void remove(int64 id)
{
m_listeners.erase(id);
}
void NotifyAll()
{
for_each(m_listeners.begin(),m_listeners.end(),[&](pair<int64,T> func){
func.second();
});
}
template<typename T1>
void NotifyAll(T1 t1)
{
for_each(m_listeners.begin(),m_listeners.end(),[&](pair<int64,T> func){
func.second(t1);
});
}
template<typename T1,typename T2>
void NotifyAll(T1 t1,T2 t2)
{
for_each(m_listeners.begin(),m_listeners.end(),[&](pair<int64,T> func){
func.second(t1,t2);
});
}
};
使用方法:
void food1(int a)
{
printf("food1 %d\n",a);
}
struct fooClass
{
void fooFunc(int a,int b)
{
printf("wocao %d %d",a,b);
}
};
main:
ut_delegate<function<void(int)>> del;
del.add(std::bind(food1,placeholders::_1));
fooClass* wo1=new fooClass();
del.add(std::bind(&fooClass::fooFunc,wo1,placeholders::_1,555));
del.NotifyAll(123);
缺点是接口不友好,你仍然需要显式使用function和bind(bind很丑陋,虽然很灵活)
这里没有使用+= -= ()之类的操作符,操作符重载看起来很酷,其实经常让人看不懂代码
类里面有一系列的NotifyAll,不过还好未被调用的模板函数不会被编译 所以这个类能正常工作
当然,还有一个老大难问题:如果你使用不正确,编译器会报出令人崩溃的编译错误
还有一个坎:function没有提供==操作符,这给remove带来很大麻烦,但是实际上应该是有方法判断函数对象相等的,因为函数对象实际上就是保存了函数指针和可能的this,
我采用直接比较内存的方法判断相等,虽然是个hack,但是能工作,完全fix这个问题需要研究代码,或者进一步测试
看了function的代码之后发现实际上function没办法提供这个功能,但是我们可以想个曲线救国的办法,绑定的时候返回一个id,外部释放的时候使用这个id来处理
但是我们仍然需要考虑生存期问题,假设现在有委托A,类B把自己的成员函数绑定到A上,那么B销毁时需要去调用remove,那么B需要持有A的指针,但是如果此时A已经销毁,所以A在销毁时需要通知B
也就是说A,B各自在销毁的时候都要去通知对方,这样又增加了很多复杂度,如果能自动管理生存期就好了!
但是如果A始终能先于B销毁就没有这个问题了
话说回来,果然还是自己抡的东西好用..
原文链接: https://www.cnblogs.com/mightofcode/archive/2013/03/13/2958159.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/80476
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!