标准C++实现C#代理机制

原文地址:点击打开链接

说明

委托和事件绝对是 .NET/C#中很酷的特性,而在标准C++上已存在很多对其模拟的尝试。本文中基于标准C++的委托类试图提供一个完整并易于使用的解决方案。


设计目标

在CodeProject中已存在几个很好的委托类实现。然而,仍然没有足够完美的方案应对广泛的开始使用。比如,一些实现中并未支持多播委托,一些不支持函数对象,而还有一些实现在应用中难以使用。所以本文的委托类的设计目标为:

*支持所有C++可调用对象,包含静态函数,成员函数以及函数对象。

*在同一个委托类中支持单播和多播委托,使使用者不必自己实现多播代理。(多播委托其调用列表中可以拥有多个元素的委托

*易于理解与使用。


例子

1、使用委托

#include "AcfDelegate.h"
using namespace Acf;

static void H() { ... }

class Foo {
public:
    void G() { ... }
};

class Foo2 {
public:
    void operator()(int n) { ... }
};

// Create delegate a which attaches to a static function
Delegate<void ()> a(&H);
assert(a == &H);

// Create delegate b which attaches
// to an instance and a member function
Foo foo;
Delegate<void ()> b(&foo, &Foo::G);
assert(b == std::make_pair(&foo, &Foo::G);

// Create delegate c from a
Delegate<void ()> c = a;
assert(c == &H);

// Create delegate d which attaches to a function object
Delegate<void (int)> d(Foo2());

// Call delegates
a();
d(100);

// Combine/remove delegates
d += &H;
d += std::make_pair(&foo, &Foo::G);
d -= std::make_pair(&foo, &Foo::G);
d -= &H;

2、使用事件

class Button {
public:
    Delegate<void ()> Click;
};

Button btn;
btn.Click += &F;
btn.Click += std::make_pair(&o, &MyObj::G);
btn.Click();
btn.Click -= std::make_pair(&o, &MyObj::G);

3、使用事件(高级)

当你需要更多的管理事件,比如你所关心的线程安全性。

class Button {
private:
    Delegate<void ()> click;
    Mutex mutex;

public:
    template <class T>
    void add_Click(const T& h) {
        ScopedLock lock(this->mutex);
        this->click += h;
    }
    template <class T>
    void remove_Click(const T& h) {
        ScopedLock lock(this->mutex);
        this->click -= h;
    }

protected:
    void OnClick() { if (this->click) this->click(); }
};

btn.add_Click(&F);
btn.add_Click(std::make_pair(&o, &MyObj::G));


委托类

namespace Acf {

template <class TSignature>
class Delegate; // no body

template <class R, class T1, class T2, ..., class TN>
class Delegate<R (T1, T2, ..., TN)> {
// Constructor/Destructor
public:
    Delegate();
    template <class TFunctor>
    Delegate(const TFunctor& f);
    template <class TPtr, class TFunctionPtr>
    Delegate(const TPtr& obj, const TFunctionPtr& mfp);
    Delegate(const Delegate& d);
    ~Delegate();

// Properties
public:
    bool IsEmpty() const;
    bool IsMulticast() const;

// Methods
public:
    template <class TFunctor>
    void Add(const TFunctor& f);
    template <class TPtr, class TFunctionPtr>
    void Add(const TPtr& obj, const TFunctionPtr& mfp);

    template <class TFunctor>
    bool Remove(const TFunctor& f);
    template <class TPtr, class TFunctionPtr>
    bool Remove(const TPtr& obj, const TFunctionPtr& mfp);

    void Clear();

// Operators
public:
    operator bool() const;
    bool operator!() const;

    template <class TFunctor>
    Delegate& operator=(const TFunctor& f);
    Delegate& operator=(const Delegate& d);

    template <class TFunctor>
    Delegate& operator+=(const TFunctor& f);

    template <class TFunctor>
    friend Delegate operator+(const Delegate& d, const TFunctor& f);
    template <class TFunctor>
    friend Delegate operator+(const TFunctor& f, const Delegate& d);

    template <class TFunctor>
    Delegate& operator-=(const TFunctor& f);

    template <class TFunctor>
    Delegate operator-(const TFunctor& f) const;

    template <class TFunctor>
    friend bool operator==(const Delegate& d, const TFunctor& f);
    template <class TFunctor>
    friend bool operator==(const TFunctor& f, const Delegate& d);

    template <class TFunctor>
    friend bool operator!=(const Delegate& d, const TFunctor& f);
    template <class TFunctor>
    friend bool operator!=(const TFunctor& f, const Delegate& d);

    R operator()(T1, T2, ..., TN) const;
};

} // namespace Acf

委托类中,TFunctor模板参数支持静态函数,成员函数(通过std::pair)以及函数对象等可调用对象。
TPtr模板参数支持普通指针(如Foo*)和智能指针(如boost::shared_ptr<Foo>).


注意

*在使用委托类的时,必须保证在你工程中支持RTTI

*委托类支持六个函数参数



源代码:

AcfDelegate.h

//-------------------------------------------------------------------------
//
// Copyright (C) 2004-2005 Yingle Jia
//
// Permission to copy, use, modify, sell and distribute this software is 
// granted provided this copyright notice appears in all copies. 
// This software is provided "as is" without express or implied warranty, 
// and with no claim as to its suitability for any purpose.
//
// AcfDelegate.h
//

#ifndef __Acf_Delegate__
#define __Acf_Delegate__

#include <stdexcept> // for std::logic_error
#include <utility> // for std::pair

// Macros for template metaprogramming

#define ACF_JOIN(a, b)        ACF_DO_JOIN(a, b)
#define ACF_DO_JOIN(a, b)     ACF_DO_JOIN2(a, b)
#define ACF_DO_JOIN2(a, b)    a##b

#define ACF_MAKE_PARAMS1_0(t)
#define ACF_MAKE_PARAMS1_1(t)    t##1
#define ACF_MAKE_PARAMS1_2(t)    t##1, ##t##2
#define ACF_MAKE_PARAMS1_3(t)    t##1, ##t##2, ##t##3
#define ACF_MAKE_PARAMS1_4(t)    t##1, ##t##2, ##t##3, ##t##4
#define ACF_MAKE_PARAMS1_5(t)    t##1, ##t##2, ##t##3, ##t##4, ##t##5
#define ACF_MAKE_PARAMS1_6(t)    t##1, ##t##2, ##t##3, ##t##4, ##t##5, ##t##6

#define ACF_MAKE_PARAMS2_0(t1, t2)
#define ACF_MAKE_PARAMS2_1(t1, t2)   t1##1 t2##1
#define ACF_MAKE_PARAMS2_2(t1, t2)   t1##1 t2##1, t1##2 t2##2
#define ACF_MAKE_PARAMS2_3(t1, t2)   t1##1 t2##1, t1##2 t2##2, t1##3 t2##3
#define ACF_MAKE_PARAMS2_4(t1, t2)   t1##1 t2##1, t1##2 t2##2, t1##3 t2##3, t1##4 t2##4
#define ACF_MAKE_PARAMS2_5(t1, t2)   t1##1 t2##1, t1##2 t2##2, t1##3 t2##3, t1##4 t2##4, t1##5 t2##5
#define ACF_MAKE_PARAMS2_6(t1, t2)   t1##1 t2##1, t1##2 t2##2, t1##3 t2##3, t1##4 t2##4, t1##5 t2##5, t1##6 t2##6

#define ACF_MAKE_PARAMS1(n, t)         ACF_JOIN(ACF_MAKE_PARAMS1_, n) (t)
#define ACF_MAKE_PARAMS2(n, t1, t2)    ACF_JOIN(ACF_MAKE_PARAMS2_, n) (t1, t2)

namespace Acf {

class InvalidCallException : public std::logic_error
{
public:
    InvalidCallException() : std::logic_error("An empty delegate is called")
    {
    }
};

template <class T>
inline static T _HandleInvalidCall()
{
    throw InvalidCallException();
}

template <>
inline static void _HandleInvalidCall<void>()
{
}

template <class TSignature>
class Delegate; // no body

} // namespace Acf

// Specializations

#define ACF_DELEGATE_NUM_ARGS	0 // Delegate<R ()>
#include "AcfDelegateTemplate.h"
#undef ACF_DELEGATE_NUM_ARGS

#define ACF_DELEGATE_NUM_ARGS	1 // Delegate<R (T1)>
#include "AcfDelegateTemplate.h"
#undef ACF_DELEGATE_NUM_ARGS

#define ACF_DELEGATE_NUM_ARGS	2 // Delegate<R (T1, T2)>
#include "AcfDelegateTemplate.h"
#undef ACF_DELEGATE_NUM_ARGS

#define ACF_DELEGATE_NUM_ARGS	3 // Delegate<R (T1, T2, T3)>
#include "AcfDelegateTemplate.h"
#undef ACF_DELEGATE_NUM_ARGS

#define ACF_DELEGATE_NUM_ARGS	4 // Delegate<R (T1, T2, T3, T4)>
#include "AcfDelegateTemplate.h"
#undef ACF_DELEGATE_NUM_ARGS

#define ACF_DELEGATE_NUM_ARGS	5 // Delegate<R (T1, T2, T3, T4, T5)>
#include "AcfDelegateTemplate.h"
#undef ACF_DELEGATE_NUM_ARGS

#define ACF_DELEGATE_NUM_ARGS	6 // Delegate<R (T1, T2, T3, T4, T5, T6)>
#include "AcfDelegateTemplate.h"
#undef ACF_DELEGATE_NUM_ARGS

#endif // #ifndef __Acf_Delegate__

AcfDelegateTemplate.h

//-------------------------------------------------------------------------
//
// Copyright (C) 2004-2005 Yingle Jia
//
// Permission to copy, use, modify, sell and distribute this software is 
// granted provided this copyright notice appears in all copies. 
// This software is provided "as is" without express or implied warranty, 
// and with no claim as to its suitability for any purpose.
//
// AcfDelegateTemplate.h
//

// Note: this header is a header template and must NOT have multiple-inclusion
// protection.

#define ACF_DELEGATE_TEMPLATE_PARAMS    ACF_MAKE_PARAMS1(ACF_DELEGATE_NUM_ARGS, class T)
	// class T0, class T1, class T2, ...
#define ACF_DELEGATE_TEMPLATE_ARGS      ACF_MAKE_PARAMS1(ACF_DELEGATE_NUM_ARGS, T)
	// T0, T1, T2, ...
#define ACF_DELEGATE_FUNCTION_PARAMS    ACF_MAKE_PARAMS2(ACF_DELEGATE_NUM_ARGS, T, a)
	// T0 a0, T1 a1, T2 a2, ...
#define ACF_DELEGATE_FUNCTION_ARGS      ACF_MAKE_PARAMS1(ACF_DELEGATE_NUM_ARGS, a)
	// a0, a1, a2, ...

// Comma if nonzero number of arguments
#if ACF_DELEGATE_NUM_ARGS == 0
#define ACF_DELEGATE_COMMA
#else
#define ACF_DELEGATE_COMMA    ,
#endif

namespace Acf {

//-------------------------------------------------------------------------
// class Delegate<R (T1, T2, ..., TN)>

template <class R ACF_DELEGATE_COMMA ACF_DELEGATE_TEMPLATE_PARAMS>
class Delegate<R (ACF_DELEGATE_TEMPLATE_ARGS)>
{
// Declaractions
private:
    class DelegateImplBase
    {
    // Fields
    public:
        DelegateImplBase* Previous; // singly-linked list

    // Constructor/Destructor
    protected:
        DelegateImplBase() : Previous(NULL) { }
        DelegateImplBase(const DelegateImplBase& other) : Previous(NULL) { }
    public:
        virtual ~DelegateImplBase() { }

    // Methods
    public:
        virtual DelegateImplBase* Clone() const = 0;
        virtual R Invoke(ACF_DELEGATE_FUNCTION_PARAMS) const = 0;
    };

    template <class TFunctor>
    struct Invoker
    {
        static R Invoke(const TFunctor& f ACF_DELEGATE_COMMA ACF_DELEGATE_FUNCTION_PARAMS)
        {
            return (const_cast<TFunctor&>(f))(ACF_DELEGATE_FUNCTION_ARGS);
        }
    };

    template <class TPtr, class TFunctionPtr>
    struct Invoker<std::pair<TPtr, TFunctionPtr> >
    {
        static R Invoke(const std::pair<TPtr, TFunctionPtr>& mf ACF_DELEGATE_COMMA ACF_DELEGATE_FUNCTION_PARAMS)
        {
            return ((*mf.first).*mf.second)(ACF_DELEGATE_FUNCTION_ARGS);
        }
    };

    template <class TFunctor>
    class DelegateImpl : public DelegateImplBase
    {
    // Fields
    public:
        TFunctor Functor;

    // Constructor
    public:
        DelegateImpl(const TFunctor& f) : Functor(f)
        {
        }
        DelegateImpl(const DelegateImpl& other) : Functor(other.Functor)
        {
        }

    // Methods
    public:
        virtual DelegateImplBase* Clone() const
        {
            return new DelegateImpl(*this);
        }
        virtual R Invoke(ACF_DELEGATE_FUNCTION_PARAMS) const
        {
            return Invoker<TFunctor>::Invoke(this->Functor ACF_DELEGATE_COMMA ACF_DELEGATE_FUNCTION_ARGS);
        }
    };

// Fields
private:
    DelegateImplBase* _last;

// Constructor/Destructor
public:
    Delegate()
    {
        this->_last = NULL;
    }

    template <class TFunctor>
    Delegate(const TFunctor& f)
    {
        this->_last = NULL;
        *this = f;
    }

	template<class TPtr, class TFunctionPtr>
    Delegate(const TPtr& obj, const TFunctionPtr& mfp)
    {
        this->_last = NULL;
        *this = std::make_pair(obj, mfp);
    }

    Delegate(const Delegate& d)
    {
        this->_last = NULL;
        *this = d;
    }

    ~Delegate()
    {
        Clear();
    }

// Properties
public:
    bool IsEmpty() const
    {
        return (this->_last == NULL);
    }

    bool IsMulticast() const
    {
        return (this->_last != NULL && this->_last->Previous != NULL);
    }

// Static Methods
private:
    static DelegateImplBase* CloneDelegateList(DelegateImplBase* list, /*out*/ DelegateImplBase** first)
    {
        DelegateImplBase* list2 = list;
        DelegateImplBase* newList = NULL;
        DelegateImplBase** pp = &newList;
        DelegateImplBase* temp = NULL;

        try
        {
            while (list2 != NULL)
            {
                temp = list2->Clone();
                *pp = temp;
                pp = &temp->Previous;
                list2 = list2->Previous;
            }
        }
        catch (...)
        {
            FreeDelegateList(newList);
            throw;
        }

        if (first != NULL)
            *first = temp;
        return newList;
    }

    static void FreeDelegateList(DelegateImplBase* list)
    {
        DelegateImplBase* temp = NULL;
        while (list != NULL)
        {
            temp = list->Previous;
            delete list;
            list = temp;
        }
    }

    static void InvokeDelegateList(DelegateImplBase* list ACF_DELEGATE_COMMA ACF_DELEGATE_FUNCTION_PARAMS)
    {
        if (list != NULL)
        {
            if (list->Previous != NULL)
                InvokeDelegateList(list->Previous ACF_DELEGATE_COMMA ACF_DELEGATE_FUNCTION_ARGS);
            list->Invoke(ACF_DELEGATE_FUNCTION_ARGS);
        }
    }

// Methods
public:
    template <class TFunctor>
    void Add(const TFunctor& f)
    {
        DelegateImplBase* d = new DelegateImpl<TFunctor>(f);
        d->Previous = this->_last;
        this->_last = d;
    }

	template<class TPtr, class TFunctionPtr>
    void Add(const TPtr& obj, const TFunctionPtr& mfp)
    {
        DelegateImplBase* d = new DelegateImpl<std::pair<TPtr, TFunctionPtr> >(std::make_pair(obj, mfp));
        d->Previous = this->_last;
        this->_last = d;
    }

    template <class TFunctor>
    bool Remove(const TFunctor& f)
    {
        DelegateImplBase* d = this->_last;
        DelegateImplBase** pp = &this->_last;
        DelegateImpl<TFunctor>* impl = NULL;

        while (d != NULL)
        {
            impl = dynamic_cast<DelegateImpl<TFunctor>*>(d);
            if (impl != NULL && impl->Functor == f)
            {
                *pp = d->Previous;
                delete impl;
                return true;
            }
            pp = &d->Previous;
            d = d->Previous;
        }
        return false;
    }

	template<class TPtr, class TFunctionPtr>
    bool Remove(const TPtr& obj, const TFunctionPtr& mfp)
    {
        return Remove(std::make_pair(obj, mfp));
    }

    void Clear()
    {
        FreeDelegateList(this->_last);
        this->_last = NULL;
    }

private:
    template <class TFunctor>
    bool Equals(const TFunctor& f) const
    {
        if (this->_last == NULL || this->_last->Previous != NULL)
            return false;

        DelegateImpl<TFunctor>* impl = 
            dynamic_cast<DelegateImpl<TFunctor>*>(this->_last);
        if (impl == NULL)
            return false;
        return (impl->Functor == f);
    }

// Operators
public:
    operator bool() const
    {
        return !IsEmpty();
    }

    bool operator!() const
    {
        return IsEmpty();
    }

    template <class TFunctor>
    Delegate& operator=(const TFunctor& f)
    {
        DelegateImplBase* d = new DelegateImpl<TFunctor>(f);
        FreeDelegateList(this->_last);
        this->_last = d;
        return *this;
    }

    Delegate& operator=(const Delegate& d)
    {
        if (this != &d)
        {
            DelegateImplBase* list = CloneDelegateList(d._last, NULL);
            FreeDelegateList(this->_last);
            this->_last = list;
        }
        return *this;
    }

    template <class TFunctor>
    Delegate& operator+=(const TFunctor& f)
    {
        Add(f);
        return *this;
    }

    template <class TFunctor>
    friend Delegate operator+(const Delegate& d, const TFunctor& f)
    {
        return (Delegate(d) += f);
    }

    template <class TFunctor>
    friend Delegate operator+(const TFunctor& f, const Delegate& d)
    {
        return (d + f);
    }

    template <class TFunctor>
    Delegate& operator-=(const TFunctor& f)
    {
        Remove(f);
        return *this;
    }

    template <class TFunctor>
    Delegate operator-(const TFunctor& f) const
    {
        return (Delegate(*this) -= f);
    }

    template <class TFunctor>
    friend bool operator==(const Delegate& d, const TFunctor& f)
    {
        return d.Equals(f);
    }

    template <class TFunctor>
    friend bool operator==(const TFunctor& f, const Delegate& d)
    {
        return (d == f);
    }

    template <class TFunctor>
    friend bool operator!=(const Delegate& d, const TFunctor& f)
    {
        return !(d == f);
    }

    template <class TFunctor>
    friend bool operator!=(const TFunctor& f, const Delegate& d)
    {
        return (d != f);
    }

    R operator()(ACF_DELEGATE_FUNCTION_PARAMS) const
    {
        if (this->_last == NULL)
            return _HandleInvalidCall<R>();

        if (this->_last->Previous != NULL)
            InvokeDelegateList(this->_last->Previous ACF_DELEGATE_COMMA ACF_DELEGATE_FUNCTION_ARGS);
        return this->_last->Invoke(ACF_DELEGATE_FUNCTION_ARGS);
    }
};

} // namespace Acf

#undef ACF_DELEGATE_TEMPLATE_PARAMS
#undef ACF_DELEGATE_TEMPLATE_ARGS
#undef ACF_DELEGATE_FUNCTION_PARAMS
#undef ACF_DELEGATE_FUNCTION_ARGS
#undef ACF_DELEGATE_COMMA

Delegate.cpp

// Delegate.cpp : Defines the entry point for the console application.
//

#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#ifdef _MSC_VER
#include <crtdbg.h>
#endif // #ifdef _MSC_VER

#include "AcfDelegate.h"
using namespace Acf;

static void H(const char* s)
{
    printf("  Static function invoked by %s\n", s);
}

class MyObject
{
public:
    int count;
    MyObject(int n) : count(n) { }

    void G(const char* s)
    {
        printf("  Member function invoked by %s\n", s);
        this->count++;
    }
};

class MyFunctor
{
public:
    void operator()(const char* s)
    {
        printf("  Functor invoked by %s\n", s);
    }
};

int main(int argc, char* argv[])
{
#ifdef _MSC_VER
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif // #ifdef _MSC_VER

    // Create an empty delegate
    printf("Invoking delegate a0:\n");
    Delegate<void ()> a0;
    a0();
    printf("\n");

    // Create delegate a that references a static function:
    Delegate<void (const char*)> a(&H);
    assert(a == &H);

    printf("Invoking delegate a:\n");
    a("a");
    printf("\n");

    // Create delegate b that references an instance function:
    MyObject myObj(0);
    Delegate<void (const char*)> b(&myObj, &MyObject::G);
    assert(b == std::make_pair(&myObj, &MyObject::G));

    printf("Invoking delegate b:\n");
    b("b");
    assert(myObj.count == 1);
    printf("\n");

    // Create delegate c that references a function object:
    MyFunctor myFunctor;
    Delegate<void (const char*)> c(myFunctor);

    printf("Invoking delegate c:\n");
    c("c");
    printf("\n");

    // Add an instance function and a functor to delegate a
    a += std::make_pair(&myObj, &MyObject::G);
    a += MyFunctor();

    printf("Invoking delegate a:\n");
    a("a");
    assert(myObj.count == 2);
    printf("\n");

    // Remove the static function from delegate a
    a -= &H;

    printf("Invoking delegate a:\n");
    a("a");
    assert(myObj.count == 3);
    printf("\n");

    // Create delegate d from a
    Delegate<void (const char*)> d(a);

    // Add delegate b to delegate d
    d += Delegate<void (const char*)>(&H);

    printf("Invoking delegate d:\n");
    d("d");
    assert(myObj.count == 4);
    printf("\n");

    getchar();

    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值