吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2051|回复: 4
收起左侧

[C&C++ 转载] C++中的事件分发器与委托

[复制链接]
雪千渔 发表于 2021-5-30 11:34
本帖最后由 雪千渔 于 2021-5-30 11:40 编辑

先看看如何使用的
[C++] 纯文本查看 复制代码
#include "CoreLib/Events.hpp"
class EventTest
{
public:
    int cb_index;
 
    Action<int> e;
    void lambda_inst(int c) {
        std::cout << "lambda_inst callback" << std::endl;
    }
    void bind_inst(int c) {
        std::cout << "bind_inst callback" << std::endl;
    }
    static void static_method(int c) {
        std::cout << "static_method callback" << std::endl;
    }
 
    EventTest()
    {
        //静态lambda两种方式
        e.AddListener([](int c) { std::cout << "static lambda1 callback" << std::endl; });
        e += [](int c) { std::cout << "static lambda2 callback" << std::endl; };
 
        //静态函数
        e += static_method; //或 e.AddListener(static_method);
        //e -= static_method; 或 e.RemoveListener(static_method);
 
        //添加与移除闭包lambda方法,可以把lambda托管给this,然后最后按实例移除
        this->cb_index = e.AddListener(this, [this](int c) { this->lambda_inst(c); });
        //e.RemoveListenerByIndex(this->cb_index);
 
        //添加与移除成员方法
        e.AddListener(this, &EventTest::bind_inst);
        //e.RemoveListener(this, &EventTest::bind_inst);
 
        //执行
        e.Invoke(3);
 
        //移除实例中的所有事件
        e.RemoveByInstance(this);
 
        //移除全部事件
        e.RemoveAllListener();
    }
};


在程序中使用批量事件通知是很常用的场景,该事件分发器可以绑定多个静态与非静态函数,内部使用标准库的list和function实现,可变模板参数可以拓展到任意长度。
模仿C#中的委托,分为Events、Delegate、Action和Function。以下是继承的结构。
  • Events (添加移除静态与实例事件)
    • Delegate (执行事件、按实例移除或全部移除)
      • Action (Delegate特化版本)
      • Function (继承Delegate,实现带返回值列表的执行事件)
      • Function<bool> (Function偏特化版本,实现返回值验证是否存在false)
  • ActionEvents (Event特化版本)
  • FunctionEvents (Event特化版本)

Events作为模板需要传入返回值与形参类型,同时Events作为基类,只能使用添加事件和移除事件,并不可以执行。而执行函数是在Delegate层以上的,因为ActionEvents和FunctionEvents只是Events的具体化,Action只是Delegate的具体化,所以就可以有以下的继承关系。
  • ActionEvents (Events)
    • Action (Delegate)
  • FunctionEvents (Events)
    • Delegate
      • Function
      • Function<bool>

Events类应该实现以下几个功能:
  • 添加与移除函数指针的事件(普通函数、成员静态函数与无捕获的lambda表达式)
  • 添加与移除实例事件(成员实例函数)
  • 通过索引来移除闭包lambda
  • 提供+=与-=运算符重载(仅函数指针类型)

Delegate类功能实现:
  • Invoke执行所有事件
  • 按实例对象移除事件
  • 移除所有事件

普通的函数指针因为在内存中仅存在一份,所以在移除时可以方便的直接对保存的函数指针进行对比。
带捕获的lambda表达式可以直接转换成std::function类型,采用索引的方式来控制:将函数保存后,返回一个自增的索引,外部可以通过这个索引来移除。或者在创建时传入一个实例对象,最后按实例移除事件。
普通的实例函数就需要使用std::bind对实例进行绑定,但是绑定后就没办法对实例和成员指针进行判断,所以使用成员指针来比较,C++的成员指针必须要求指定的类型,所以使用类模板,并通过继承来做类型擦除,类型擦除后就可以将它们保存到一起,同时取值函数也是一个模板函数,在取值时对实例进行基类至子类的转换。
所有事件的绑定绑定都会返回一个索引值,用来标示该事件,主要用于没有名字函数的移除,在单独移除事件时需要该索引值,在不需要移除单事件或移除全部的情况下该索引可以丢弃。

该源码你可以在 https://github.com/Jayshonyves/JxCode.CoreLib/blob/main/CoreLib/Events.hpp 找到。
博客文章页:http://www.imxqy.com/code/cpp/events.html

[C++] 纯文本查看 复制代码
#ifndef CORELIB_EVENTS_HPP
#define CORELIB_EVENTS_HPP
 
#include <list>
#include <functional>
 
template<typename TReturn, typename... TArgs>
class Events
{
public:
    using FunctionType = std::function<TReturn(TArgs...)>;
    using FunctionPointer = TReturn(*)(TArgs...);
 
protected:
    enum class FunctionInfoType
    {
        Static,
        Lambda,
        Member
    };
    class FunctionInfo
    {
    public:
        unsigned int index;
        FunctionInfoType type;
    public:
        FunctionInfo(const unsigned int& index, const FunctionInfoType& type)
            : index(index), type(type)
        {
        }
    public:
        bool operator ==(const FunctionInfo& r) {
            return this->index == r.index;
        }
        virtual TReturn Invoke(TArgs...) = 0;
    };
    class StaticFunctionInfo : public FunctionInfo
    {
    public:
        FunctionPointer ptr;
        StaticFunctionInfo(const unsigned int& index, FunctionPointer ptr)
            : FunctionInfo(index, FunctionInfoType::Static), ptr(ptr)
        {
        }
        virtual TReturn Invoke(TArgs... args) override {
            return ptr(args...);
        }
    };
    class LambdaFunctionInfo : public FunctionInfo
    {
    public:
        FunctionType func;
        void* instance;
        LambdaFunctionInfo(
            const unsigned int& index,
            void* instance,
            const FunctionType& func)
            : FunctionInfo(index, FunctionInfoType::Lambda), instance(instance), func(func)
        {
        }
        virtual TReturn Invoke(TArgs... args) override {
            return func(args...);
        }
    };
    template<typename TObj>
    class MemberFunctionInfo : public FunctionInfo
    {
    public:
        TObj* instance;
        TReturn(TObj::* ptr)(TArgs...);
 
        MemberFunctionInfo(
            const unsigned int& index,
            TObj* instance,
            TReturn(TObj::* ptr)(TArgs...))
            : FunctionInfo(index, FunctionInfoType::Member), instance(instance), ptr(ptr)
        {
        }
        virtual TReturn Invoke(TArgs... args) override {
            return (instance->*ptr)(args...);
        }
    };
 
protected:
    unsigned int index;
    std::list<FunctionInfo*> eventList;
public:
    int Count() const {
        return this->eventList.size();
    }
public:
    Events() : index(0) {}
    Events(const Events& right) = delete;
    Events(Events&& right) = delete;
    ~Events() {
        this->RemoveAllListener();
    }
protected:
    void RemoveAllListener() {
        for (auto it = this->eventList.begin(); it != this->eventList.end(); it++) {
            delete* it;
        }
        this->eventList.clear();
    }
public:
    //static
    unsigned int AddListener(FunctionPointer funcPtr) {
        if (funcPtr == nullptr) {
            return 0;
        }
        this->eventList.push_back(new StaticFunctionInfo(++this->index, funcPtr));
        return this->index;
    }
    //member
    template<typename TObj>
    unsigned int AddListener(TObj* obj, TReturn(TObj::* ptr)(TArgs...)) {
        if (obj == nullptr) {
            return 0;
        }
        this->eventList.push_back(new MemberFunctionInfo<TObj>(++this->index, obj, ptr));
        return this->index;
    }
    //lambda
    template<typename TObj>
    unsigned int AddListener(TObj* obj, const FunctionType& func) {
        this->eventList.push_back(new LambdaFunctionInfo(++this->index, obj, func));
        return this->index;
    }
 
    //static
    unsigned int RemoveListener(FunctionPointer funcPtr) {
        for (auto it = this->eventList.begin(); it != this->eventList.end(); it++) {
            if ((*it)->type == FunctionInfoType::Static
                && static_cast<StaticFunctionInfo*>(*it)->ptr == funcPtr) {
                auto index = (*it)->index;
                delete* it;
                this->eventList.erase(it);
                return index;
            }
        }
        return 0;
    }
    //member
    template<typename TObj>
    unsigned int RemoveListener(TObj* obj, TReturn(TObj::* ptr)(TArgs...)) {
        for (auto it = this->eventList.begin(); it != this->eventList.end(); it++)
        {
            if ((*it)->type == FunctionInfoType::Member
                && static_cast<MemberFunctionInfo<TObj>*>(*it)->instance == obj
                && static_cast<MemberFunctionInfo<TObj>*>(*it)->ptr == ptr)
            {
                auto index = (*it)->index;
                delete* it;
                this->eventList.erase(it);
                return index;
            }
        }
        return 0;
    }
 
 
    unsigned int RemoveListenerByIndex(unsigned int index) {
        if (index <= 0) {
            return 0;
        }
        for (auto it = this->eventList.begin(); it != this->eventList.end(); it++) {
            if ((*it)->index == index) {
                delete* it;
                this->eventList.erase(it);
                return index;
            }
        }
        return 0;
    }
 
    unsigned int operator+=(FunctionPointer ptr) {
        return this->AddListener(ptr);
    }
 
    unsigned int operator-=(FunctionPointer ptr) {
        return this->RemoveListener(ptr);
    }
};
 
template<typename TReturn, typename... TArgs>
class Delegate : public Events<TReturn, TArgs...>
{
    using  base = Events<TReturn, TArgs...>;
public:
    void Invoke(TArgs... t) {
        for (auto& item : this->eventList) {
            item->Invoke(t...);
        }
    }
 
    void RemoveAllListener() {
        base::RemoveAllListener();
    }
 
    //member lambda
    template<typename TObj>
    void RemoveByInstance(TObj* obj) {
        using MemberFunInfo = typename Events<TReturn, TArgs...>::template MemberFunctionInfo<TObj>;
        using LambdaFunInfo = typename Events<TReturn, TArgs...>::LambdaFunctionInfo;
 
        for (auto it = this->eventList.begin(); it != this->eventList.end(); ) {
            if ((
                (*it)->type == base::FunctionInfoType::Member
                && (static_cast<MemberFunInfo*>(*it))->instance == obj
                ) || (
                (*it)->type == base::FunctionInfoType::Lambda
                && static_cast<LambdaFunInfo*>(*it)->instance == obj
                )
                )
            {
                delete* it;
                it = this->eventList.erase(it);
            }
            else {
                it++;
            }
        }
    }
};
 
template<typename... TArgs>
using ActionEvents = Events<void, TArgs...>;
 
template<typename... TArgs>
using Action = Delegate<void, TArgs...>;
 
template<typename TReturn, typename... TArgs>
using FunctionEvents = Events<TReturn, TArgs...>;
 
template<typename TReturn, typename... TArgs>
class Function : public Delegate<TReturn, TArgs...>
{
public:
    std::vector<TReturn> InvokeResult(TArgs... args) {
        std::vector<TReturn> retList;
        for (auto& item : this->eventList) {
            retList.push_back(item->Invoke(args...));
        }
        return retList;
    }
};
 
template<>
class Function<bool> : public Delegate<bool>
{
public:
    std::vector<bool> InvokeResult() {
        std::vector<bool> retList;
        for (auto& item : this->eventList) {
            retList.push_back(item->Invoke());
        }
        return retList;
    }
 
    bool IsValidReturnInvoke() {
        for (const bool& item : this->InvokeResult()) {
            if (!item) return false;
        }
        return true;
    }
};
 
 
#endif // !CORELIB_EVENTS_HPP

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

sqzh 发表于 2021-5-30 14:58
学习技术,谢谢
nappywu 发表于 2021-6-22 22:59
leepop 发表于 2021-6-24 16:30
发现了一个c++大佬,github库看起来很厉害,比较小白,有没有应用使用的场景,是不是可以辅助优化我的代码。
 楼主| 雪千渔 发表于 2021-7-1 19:32
leepop 发表于 2021-6-24 16:30
发现了一个c++大佬,github库看起来很厉害,比较小白,有没有应用使用的场景,是不是可以辅助优化我的代码 ...

就是一个基础型的库,给了个统一的Object,UTF8字符串,指针托管的内存管理方式,还有反射,做序列化比较方便。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 16:35

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表