C++ 之 委托模式

  • Post author:
  • Post category:其他



原文地址



成员函数指针

class A{                       
public:
 
    void Func(int){            
        std::cout << "I am in A" << std::endl;
    }                          
};
void (A::*pFunc)(int) = &A::Func;



使用模板类

template <typename T>
class DelegateHandler{
public:
    DelegateHandler(T *pT, void (T::*pFunc)(int)) : m_pT(pT),
                m_pFunc(pFunc){}
 
    void Invoke(int value){
        (m_pT->*m_pFunc)(value);
    }
 
private:
    T *m_pT;
    void (T::*m_pFunc)(int);
};
A a;
DelegateHandler<A> dha(&a, &A::Func);
dha.Invoke(3);
 
B b;
DelegateHandler<B> dhb(&b, &B::Method);   //B::Method的声明与A::Func类似
dhb.Invoke(4);

到这里产生了一个问题:如果希望调用的目标是非成员函数,怎么办?上面的类模板无法调用非成员函数,不过使用

模板偏特化

就可以解决这个问题:

template<>
class DelegateHandler<void>{  //void代替前面的类型T,表示类模板没有参数
 
public:
    DelegateHandler(void(*pFunc)(int)) : m_pFunc(pFunc){}
 
    void Invoke(int value){
        (*m_pFunc)(value);
    }
 
private:
    void(*m_pFunc)(int);
};

非成员函数的使用方法:

void NonmemberFunc(int param){
    std::cout << "I am in NonmemberFunc!" << std::endl;
}
 
DelegateHandler<void> dhf(NonmemberFunc);
dhf.Invoke(5);



使用多态

对于单目标的委托来说,使用上面的代码或许就已经足够了。但是我的目的当然不止于此,我想要的是多目标的委托。多目标委托其实就是一个容器,在这个容器里可以存放多个对象(这里的对象指的是委托对象,不是A也不是B),当调用委托的时候依次调用每个对象。容器里的对象应该都是相同的类型,这样才能够放到强类型的容器中;而且委托调用方不应该知道具体的调用目标是什么,所以这些对象也应该要隐藏具体的细节。遗憾的是,上一步中实现的类模板都不具备这些能力,DelegateHandler和DelegateHandler

是不同的类型,不能放到同一个容器中,调用方要调用它们也必须知道调用的目标是什么类型。

解决这个问题的方法就是使用多态,令所有的委托目标类都继承一个公共的接口,调用方只通过这个接口来进行调用,这样就不必知道每个目标(这里的目标还是指的委托)具体的类型。下面就是该接口的定义

class IDelegateHandler{
public:
    virtual ~IDelegateHandler(){}
    virtual void Invoke(int) = 0;
};

然后令DelegateHandler继承该接口:

template<typename T>
class DelegateHandler : public IDelegateHandler{
public:
    DelegateHandler(T *pT, void (T::*pFunc)(int)) : m_pT(pT),
        m_pFunc(pFunc){}
 
    virtual void Invoke(int value) override {
        (m_pT->*m_pFunc)(value);
    }
 
private:
    T *m_pT;
    void (T::*m_pFunc)(int);
 
};
 
template<>
class DelegateHandler<void> : public IDelegateHandler{
public:
    DelegateHandler(void (*pFunc)(int)) : m_pFunc(pFunc){}
    virtual void Invoke(int value) override{
        (*m_pFunc)(value);
    }
private:
    void (*m_pFunc)(int);
 
};

现在可以将各种类型的DelegateHandler放到同一个容器中,并使用同样的方式来调用了:

A a;
B b;
DelegateHandler<A> dha(&a, &A::*Func);
DelegateHandler<B> dhb(&b, &B::*Method);
DelegateHandler<void> dhf(NonmemberFunc);
 
std::vector<IDelegateHandler*> handlers;
handlers.push_back(&dha);
handlers.push_back(&dhb);
handlers.push_back(&dhf);
 
//这里的auto等于std::vector<IDelegateHandler*>::const_iterator
for (auto itor = handlers.cbegin(); itor != handlers.cend(); ++itor){
    (*itor)->Invoke(7);
}