C++实现委托机制(二)

C++实现委托机制(二)
1.引言:

             上一篇文章已经介绍了如何构建一个无参数无返回值的函数指针的委托,这篇文章将对上一文章所述委托进行扩展,使得可以注册任意函数指针,不过再讲篇内容之前先要介绍一下实现这个功能所需要了解的C++11的一个新特性———可变参数模板。

2.可变参数模板:

             template(模板)是源于将类型和实现(算法)分离开的思想,为了让写好的算法适用于更多类型使得出现了模板,模板使得参数类别任意化,如果再加上“参数个数的任意化”,那么在参数方面的设计手段就基本上齐备了,有了variadic template 显然可以让设计出来的函数或是类有更大的复用性。因为有很多处理都是与“处理对象的个数”关系不大的,比如说打屏(printf),比如说比较大小(max,min),比如函数绑定子(bind,function要对应各种可能的函数就要能“任意”参数个数和类型)。如果不能对应任意个参数,那么就总会有人无法重用已有的实现,而不得不再重复地写一个自己需要的处理,而共通库的实现者为了尽可能地让自己写的类(函数)能复用在更多的场景,也不得不重复地写很多的代码或是用诡异的技巧,宏之类的去实现有限个“任意参数”的对应。
             所以在C++11中引入了这个新语法,下面我们先看一个例子,了解基本的语法:

template<typename ... Params> class MyClass;

MyClass<int, string> a;
            
 在上面这个例子我们可以看到,在定义和申明中用 typename...  表示一个参数包,这样我们使用的时候,传入一个<int,string>那么int,string就会被打包入Params中。恩,你可以吧这个参数包看做一个参数的结构体,并且这个结构体的大小是动态的,并且是匿名的。恩,也就是说你无法使用Params[0]这样的语法去随机调用某个类型。听到这里,觉得是匿名的那应该怎么使用呢?答案是递归展开!!!我们先来看一个函数的例子,假如我想写一个Max函数求传入所有参数的最大值,这个参数支持(int,double,float),返回值为double.那么函数原型你觉得大概可能是这样子的:

template<typename ...Params>
double Max(Params... _params)
{
    double Maxnum;

    //求解过程

    return Maxnum;
}
    
     但是这样写你会发现你无法获取到任何传入参数的类型和值。恩,所以我们来看下如何使用递归来获得每个参数的类型和值。

template<typename Head,typename ...Tail>
double Max(Head first,Tail... rest)
{
    double Maxnum;
    Maxnum = Max(rest...);
    if (Maxnum < first)
        Maxnum = first;
    return Maxnum;
}

     可以看到,我将函数参数分离了一个出来作为Head,这样我就可以每次处理一个变量,使用递归下降,每次递归减少一个参数。注意:上面的rest...表示参数展开,也就是说将这个参数包展开然后当做参数传进去。但是这样做还是不够的,大家都知道递归需要一个出口。所以说我们需要一个重载版本(因为模板函数不能偏特化)。

template<typename Head>
double Max(Head first)
{
    return first;
}

     这样就有了一个递归出口了。好,我们结合以上的代码写成一个完整的程序,看下如何使用的:

#include<iostream>
using namespace std;

template<typename Head, typename ...Tail>
double Max(Head first, Tail... rest)
{
    double Maxnum=0;
    Maxnum = Max(rest...);
    if (Maxnum < first)
        Maxnum = first;
    return Maxnum;
}
template<typename Head>
double Max(Head first)
{
    return first;
}

int main()
{
    cout << Max(1, 3, 3.4, 5.1, 1.5);
}

     输出结果是: 5.1,同样的,模板类是通过私有继承来实现递归的。
     
template<typename Head, typename... Tail>
class tuple<Head, Tail...> : private tuple<Tail...>{
    Head head;
public:
    /* implementation */
};
template<typename Head>
class tuple<Head> {
    /* one-tuple implementation */
};

     以上可变参数的基本内容就讲完了,如果还有不懂的可以自行百度

3.任意参数个数、返回值任意的函数指针委托:

     同样的,我们还是先对接口进行修改,因为函数指针再不是void(*)(void)所以,接口也需要是一个模板类,而且还需要是一个可变参数模板。

template<typename ReturnType, typename ...ParamType>
class IDelegate
{
public:
    IDelegate(){}
    virtual ~IDelegate(){}
    virtual bool isType(const std::type_info& _type) = 0;
    virtual ReturnType invoke(ParamType ... params) = 0;
    virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const = 0;
};

     这样,这个接口的invoke函数将会是根据你的函数类型来动态生成对应的模板了。
     同样的,我们把剩下三个类按照如此进行改造:
//StaticDelegate 普通函数的委托

template<typename ReturnType, typename ...ParamType>
class CStaticDelegate :
    public IDelegate<ReturnType, ParamType...>
{
public:

    typedef  ReturnType(*Func)(ParamType...);

    CStaticDelegate(Func _func) : mFunc(_func) { }

    virtual bool isType(const std::type_info& _type) { return typeid(CStaticDelegate<ReturnType, ParamType...>) == _type; }

    virtual ReturnType invoke(ParamType ... params) { return mFunc(params...); }

    virtual bool compare(IDelegate<ReturnType, ParamType ...> *_delegate)const
    {
        if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate<ReturnType, ParamType ...>))) return false;
        CStaticDelegate<ReturnType, ParamType ...> * cast = static_cast<CStaticDelegate<ReturnType, ParamType ...>*>(_delegate);
        return cast->mFunc == mFunc;
    }

    virtual ~CStaticDelegate(){}
private:
    Func mFunc;
};

//成员函数委托
template<typename T, typename ReturnType, typename ...ParamType>
class CMethodDelegate :
    public IDelegate<ReturnType, ParamType...>
{
public:
    typedef ReturnType(T::*Method)(ParamType...);

    CMethodDelegate(T * _object, Method _method) : mObject(_object), mMethod(_method) { }

    virtual bool isType(const std::type_info& _type) { return typeid(CMethodDelegate<T, ReturnType, ParamType...>) == _type; }

    virtual ReturnType invoke(ParamType...params)
    {
        (mObject->*mMethod)(params...);
    }

    virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const
    {
        if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate<ReturnType, ParamType...>))) return false;
        CMethodDelegate<ReturnType, ParamType...>* cast = static_cast<CMethodDelegate<ReturnType, ParamType...>*>(_delegate);
        return cast->mObject == mObject && cast->mMethod == mMethod;
    }

    CMethodDelegate(){}
    virtual ~CMethodDelegate(){}
private:
    T * mObject;
    Method mMethod;
};

//多播委托
template<typename ReturnType, typename ...ParamType>
class CMultiDelegate
{

public:

    typedef std::list<IDelegate<ReturnType, ParamType...>*> ListDelegate;
    typedef typename ListDelegate::iterator ListDelegateIterator;
    typedef typename ListDelegate::const_iterator ConstListDelegateIterator;

    CMultiDelegate() { }
    ~CMultiDelegate() { clear(); }

    bool empty() const
    {
        for (ConstListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
        {
            if (*iter) return false;
        }
        return true;
    }

    void clear()
    {
        for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
        {
            if (*iter)
            {
                delete (*iter);
                (*iter) = nullptr;
            }
        }
    }

    CMultiDelegate<ReturnType, ParamType...>& operator+=(IDelegate<ReturnType, ParamType...>* _delegate)
    {
        for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
        {
            if ((*iter) && (*iter)->compare(_delegate))
            {
                delete _delegate;
                return *this;
            }
        }
        mListDelegates.push_back(_delegate);
        return *this;
    }

    CMultiDelegate<ReturnType, ParamType...>& operator-=(IDelegate<ReturnType, ParamType...>* _delegate)
    {
        for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
        {
            if ((*iter) && (*iter)->compare(_delegate))
            {
                if ((*iter) != _delegate) delete (*iter);       //避免同一个地址被delete两次
                (*iter) = 0;
                break;
            }
        }
        delete _delegate;
        return *this;
    }

    std::vector<ReturnType> operator()(ParamType... params)
    {
        ListDelegateIterator iter = mListDelegates.begin();
        std::vector<ReturnType> _Results;
        while (iter != mListDelegates.end())
        {
            if (0 == (*iter))
            {
                iter = mListDelegates.erase(iter);
            }
            else
            {
                _Results.push_back((*iter)->invoke(params...));
                ++iter;
            }
        }
        return _Results;
    }
private:
    CMultiDelegate<ReturnType, ParamType...>(const CMultiDelegate& _event);
    CMultiDelegate<ReturnType, ParamType...>& operator=(const CMultiDelegate& _event);

private:
    ListDelegate mListDelegates;
};

     但是这样写你会发现你在newDelegate里面对于传来的函数指针进行new CStaticDelegate或者new CMethodDelegate的时候需要制定函数返回值、参数的个数和类型,这显然不满足动态类型演化。这时候我们想,能不能给定一个函数指针,让代码自动去识别这个函数的返回值和参数呢?答案是可以的,我们只需要对上面的CStaticDelegate和CMethodDelegate特化一个版本即可。
     这里使用了一个小技巧:通过函数指针去得到函数返回值、参数个数类型。详情可以看看这里:http://bbs.csdn.net/topics/390652170?page=1
     这里我就直接贴我写好的代码:
//普通函数的委托特化版本
template<typename ReturnType, typename ...ParamType>
class CStaticDelegate<ReturnType(*)(ParamType ...)> :
    public IDelegate<ReturnType, ParamType ...>
{
public:

    //定义 Func 为 void (void) 函数类型指针。
    typedef  ReturnType(*Func)(ParamType...);

    CStaticDelegate(Func _func) : mFunc(_func) { }

    virtual bool isType(const std::type_info& _type) { return typeid(CStaticDelegate<ReturnType(*)(ParamType ...)>) == _type; }

    virtual ReturnType invoke(ParamType ... params) { return mFunc(params...); }

    virtual bool compare(IDelegate<ReturnType, ParamType ...> *_delegate)const
    {
        if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate<ReturnType(*)(ParamType ...)>))) return false;
        CStaticDelegate<ReturnType(*)(ParamType ...)> * cast = static_cast<CStaticDelegate<ReturnType(*)(ParamType ...)>*>(_delegate);
        return cast->mFunc == mFunc;
    }

    virtual ~CStaticDelegate(){}
private:
    Func mFunc;
};

//成员函数委托特化
template<typename T, typename ReturnType, typename ...ParamType>
class CMethodDelegate<T,ReturnType (T:: *)(ParamType...)> :
    public IDelegate<ReturnType, ParamType...>
{
public:
    typedef ReturnType(T::*Method)(ParamType...);

    CMethodDelegate(T * _object, Method _method) : mObject(_object), mMethod(_method) { }

    virtual bool isType(const std::type_info& _type) { return typeid(CMethodDelegate<T,ReturnType(T:: *)(ParamType...)>) == _type; }

    virtual ReturnType invoke(ParamType...params)
    {
        return (mObject->*mMethod)(params...);
    }

    virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const
    {
        if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate<T, ReturnType(T:: *)(ParamType...)>))) return false;
        CMethodDelegate<T, ReturnType(T:: *)(ParamType...)>* cast = static_cast<CMethodDelegate<T, ReturnType(T:: *)(ParamType...)>*>(_delegate);
        return cast->mObject == mObject && cast->mMethod == mMethod;
    }

    CMethodDelegate(){}
    virtual ~CMethodDelegate(){}
private:
    T * mObject;
    Method mMethod;
};

     这样我生成的时候只需要new CStaticDelegate<decltype(Func)>(Func),而特化版本的可以自动识别这个Func的返回值、参数个数和类型。
     最后我给出newDelegate的代码:

template< typename T>
CStaticDelegate<T>* newDelegate(T func)
{
    return new CStaticDelegate<T>(func);
}
template< typename T,typename F>
CMethodDelegate<T,F>* newDelegate(T * _object, F func)
{
    return new CMethodDelegate<T, F>(_object, func);
}

     写到这里基本上可变参数的委托就完成了,不过还需要注意一点就是void无返回值类型多播委托需要特殊处理。所以我们还需要一个多播委托对于ReturnType为void这个情况的特化。

template< typename ...ParamType>
class CMultiDelegate<void, ParamType...>
{

public:

    typedef std::list<IDelegate<void, ParamType...>*> ListDelegate;
    typedef typename ListDelegate::iterator ListDelegateIterator;
    typedef typename ListDelegate::const_iterator ConstListDelegateIterator;

    CMultiDelegate() { }
    ~CMultiDelegate() { clear(); }

    bool empty() const
    {
        for (ConstListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
        {
            if (*iter) return false;
        }
        return true;
    }

    void clear()
    {
        for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
        {
            if (*iter)
            {
                delete (*iter);
                (*iter) = nullptr;
            }
        }
    }

    CMultiDelegate<void, ParamType...>& operator+=(IDelegate<void, ParamType...>* _delegate)
    {
        for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
        {
            if ((*iter) && (*iter)->compare(_delegate))
            {
                delete _delegate;
                return *this;
            }
        }
        mListDelegates.push_back(_delegate);
        return *this;
    }

    CMultiDelegate<void, ParamType...>& operator-=(IDelegate<void, ParamType...>* _delegate)
    {
        for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
        {
            if ((*iter) && (*iter)->compare(_delegate))
            {
                if ((*iter) != _delegate) delete (*iter);       //避免同一个地址被delete两次
                (*iter) = 0;
                break;
            }
        }
        delete _delegate;
        return *this;
    }

    void operator()(ParamType... params)
    {
        ListDelegateIterator iter = mListDelegates.begin();
        while (iter != mListDelegates.end())
        {
            if (0 == (*iter))
            {
                iter = mListDelegates.erase(iter);
            }
            else
            {
                (*iter)->invoke(params...);
                ++iter;
            }
        }
    }
private:
    CMultiDelegate<void, ParamType...>(const CMultiDelegate& _event);
    CMultiDelegate<void, ParamType...>& operator=(const CMultiDelegate& _event);

private:
    ListDelegate mListDelegates;
};

     所有代码都已经贴出来了,我把这些模板全部放到了MyDelegate.h头文件中。下面给一个使用的例子:
  
     
#include "MyDelegate.h"
using namespace Delegate;  

void NormalFunc(int a)
{
    printf("这里是普通函数 :%d\n", a);
}  

class A
{
public:
    static void StaticFunc(int a)
    {
        printf("这里是成员静态函数 : %d\n", a);
    }
    void MemberFunc(int a)
    {
        printf("这里是成员非静态函数 : %d\n", a);
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    //首先创建了一个返回值为 void ,参数为int 的一个委托。
    CMultiDelegate<void, int> e;  

    //将三个函数注册到该委托中
    e += newDelegate(NormalFunc);
    e += newDelegate(A::StaticFunc);
    e += newDelegate(&A(), &A::MemberFunc);  

    //调用
    e(1);  

    return 0;
}
        
下面这里是我写好的头文件下载地址:
链接: http://pan.baidu.com/s/1jHMglKU 密码: tm8e

原文地址:https://www.cnblogs.com/leijiangtao/p/12059501.html

时间: 2024-10-10 17:03:44

C++实现委托机制(二)的相关文章

C++实现委托机制(一)

1.引言: 如果你接触过C#,你就会觉得C#中的delegate(委托)十分灵巧,它的用法上和C\C++的函数指针很像,但是却又比C\C++的函数指针更加灵活.并且委托可以一对多,也就是可以注册多个函数,甚至是某个类的非静态成员函数.而实现事件消息机制[1]也十分依赖于委托机制.基于这样的目的,我们试着在C++上封装出这样的一个委托机制. [1]值得注意的是这里的委托事件模式与Windows的消息循环体系是不同的,通常Windows的消息是放到消息队列中,应用程序进程从队列中得到消息,然后调用消

java类加载器学习2——自定义类加载器和父类委托机制带来的问题

一.自定义类加载器的一般步骤 Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制.一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载器.如果父类加载器加载不了,依次再使用其子类进行加载.当然这类所说的父类加载器,不一定他们之间是继承的关系,有可能仅仅是包装的关系. Java之所以出现这条机制,因为是处于安全性考虑.害怕用户自己定义class文件然后自己写一个类加载器来加载原本应该是JVM自己加载的类.这样会是JVM虚拟机混乱或者

【正文】Java类加载器( CLassLoader ) 死磕 4: 神秘的双亲委托机制

[正文]Java类加载器(  CLassLoader ) 死磕4:  神秘的双亲委托机制 本小节目录 4.1. 每个类加载器都有一个parent父加载器 4.2. 类加载器之间的层次关系 4.3. 类的加载次序 4.4 双亲委托机制原理与沙箱机制 4.5. forName方法和loadClass方法的关系 4.6. 使用组合而不用继承 4.7. 各种不同的类加载途径 4.1.每个类加载器都有一个parent父加载器 每个类加载器都有一个parent父加载器,比如加载SystemConfig.cl

类加载的父亲委托机制

我们都知道.类加载器用来把类加载到java虚拟机.从JDK2.0开始,类的加载过程采用父亲委托机制.JVM的ClassLoader采用的是树形结构,除了根类加载器以外,每个ClassLoader都会有且仅有一个父类加载器,用户自定义的ClassLoader默认的父类加载器是系统类加载器,当然你可以自己指定需要用个ClassLoader的实例,我们来看他们的父子关系: 父类委托机制中,当一个java程序请求加载器loader1加载Hello类时,loader1首先委托自己的父亲加载器加载hello

在Unity中使用事件/委托机制(event/delegate)进行GameObject之

欢迎来到unity学习.unity培训.unity企业培训教育专区,这里有很多U3D资源.U3D培训视频.U3D教程.U3D常见问题.U3D项目源码,[狗刨学习网]unity极致学院,致力于打造业内unity3d培训.学习第一品牌. 一对多的观察者模式机制有什么缺点? 如果你对如何在Unity中使用事件/委托机制还不太了解,建议您查看我的前一篇文章:[Unity3D技巧]在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 在前一篇博客里面,我们写到

JQuery中的事件委托机制:delegate和undelegate

考虑下面这种场景:如果1个div下面有3个button,点击每个按钮的时候,需要打印出当前按钮的ID. <div id="parent"> <input type="button" id="a" value="1"></input> <input type="button" id="b" value="2"></i

android binder 机制二(client和普通server)

在讲它们之间的通信之前,我们先以MediaServer为例看看普通Server进程都在干些什么. int main() { -- // 获得ProcessState实例 sp<ProcessState> proc(ProcessState::self()); // 得到ServiceManager的Binder客户端实例 sp<IServiceManager> sm = defaultServiceManager(); -- // 通过ServiceManager的Binder客户

Solr4.8.0源码分析(19)之缓存机制(二)

Solr4.8.0源码分析(19)之缓存机制(二) 前文<Solr4.8.0源码分析(18)之缓存机制(一)>介绍了Solr缓存的生命周期,重点介绍了Solr缓存的warn过程.本节将更深入的来介绍下Solr的四种缓存类型,以及两种SolrCache接口实现类. 1.SolrCache接口实现类 前文已经提到SolrCache有两种接口实现类:solr.search.LRUCache 和 solr.search.LRUCache. 那么两者具体有啥区别呢? 1.1 solr.search.LR

java类加载器和父类委托机制

1.类加载器 Java虚拟机中可以安装多个类加载器,系统默认主要三个类加载器,每个类负责加载特定位置的类:BootStrap(内嵌在java虚拟机中由C++编写),ExtClassLoader,AppClassLoader.当然也可以自定义类加载器,自定义的加载器必须继承ClassLoader. Java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象或者默认采用系统类加载器为其父级类加载. 2.下面我们来看如下一段代码: p