在c++中用function与bind实现委托

委托的核心就是封装类成员函数,使不同类的不同函数能够以一种统一的方式被调用

这样进行回调的方式要比使用接口通知模型少写很多代码,避免了重复工作

如果不使用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

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午7:34
下一篇 2023年2月9日 下午7:34

相关推荐