用于C ++的自定义运行时类型系统/库

时间:2012-01-19 16:24:09

标签: c++ rtti

在我正在制作的应用程序中,我有一个EventDispatcher类,可以使用基类Event类。调度程序不是模板化的,它适用于每个事件的运行时类型;这是为了允许脚本从基类Event类继承并创建自己的事件类型。

它也喜欢这个事件调度程序来处理事件的继承。例如,我FooEvent继承自FooBaseEvent;每当FooEvent发生时,对FooBaseEvent感兴趣的回调也会得到通知,但不会反过来。

是否有任何图书馆可以让这更容易?请记住,继承检查也应该扩展到脚本中定义的事件。

(脚本语言是Python,但这并不重要。)


修改:我的EventDispatcher具有以下界面(Python):

class EventDispatcher:
    def subscribe(self, event_type, callback) -> EventDispatcher.Subscription
    def post(self, event)

    class Subscription:
        def cancel(self)
        def alive(self) -> bool

1 个答案:

答案 0 :(得分:0)

我不知道任何图书馆会让你的生活更轻松,但这并不能证明它不存在。也就是说,Python和C ++的类型系统有一些重要的区别,因此找到一个通用的类型信息系统来桥接这两者可能有点棘手。

如果您只想跟踪继承层次结构并准备手动注册类型,则可以相对快速地自行注册。以下记录了type_registry_t中的层次结构,然后dispatcher_t查看层次结构以查看侦听器是否对事件感兴趣。注意使用一些c ++ 11功能。

#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <map>
#include <vector>

typedef std::string class_id_t;

class type_registry_t {
    std::multimap<class_id_t, class_id_t> parent_;
public:
    void register_type(class_id_t const& id, std::vector<class_id_t> const& parent)
    {
        for (size_t i = 0, sz = parent.size(); i < sz; ++i)
            parent_.insert(std::make_pair(id, parent[i]));
    }

    template <class out_t>
    out_t all_parents(class_id_t const& id, out_t out) const
    {

        for (auto r = parent_.equal_range(id); r.first != r.second; ++r.first) {
            *out++ = r.first->second;
            out = all_parents(r.first->second, out);
        }

        return out;
    }
};

class event_t {
public:
    virtual class_id_t id() const = 0;
    virtual std::vector<class_id_t> parent() const = 0;
};

inline void register_type(type_registry_t& r, event_t const& e)
{
    r.register_type(e.id(), e.parent());
}

class listener_t {
    std::vector<class_id_t> listen_for_;

protected:
    listener_t(std::vector<class_id_t> const& listen_for)
    :   listen_for_ (listen_for)
    { }

public: 

    std::set<class_id_t> listen_for(type_registry_t const& reg) const
    {
        std::set<class_id_t> s;
        for (size_t i = 0, sz = listen_for_.size(); i < sz; ++i) {
            s.insert(listen_for_[i]);
            reg.all_parents(listen_for_[i], std::inserter(s, s.end()));
        }
        return s;
    }

    virtual void notify(event_t const&) = 0; 
};

class dispatcher_t {
    type_registry_t const* reg_;
    std::vector<std::shared_ptr<listener_t>> listener_;
public:
    dispatcher_t(type_registry_t const& reg)
    :   reg_ (&reg)
    { }

    void connect(std::shared_ptr<listener_t> const listener)
    {
        listener_.push_back(listener);
    }

    void signal(event_t& event)
    {
        class_id_t const id = event.id();
        for (size_t i = 0, sz = listener_.size(); i < sz; ++i) {
            std::set<class_id_t> const s = listener_[i]->listen_for(*reg_);

            if (s.find(id) != s.end())
                listener_[i]->notify(event);
        }
    }
};

这使您可以根据事件在层次结构中的位置来执行事件选择。如下所示(我认为你在你的例子中描述了这一点)。

struct foo_base_event_t : event_t {
    class_id_t id() const { return "foo_base_event_t"; }
    std::vector<class_id_t> parent() const
    { 
        std::vector<class_id_t> r;
        r.push_back("event_t");
        return r;
    }
};

struct foo_event_t : foo_base_event_t {
    class_id_t id() const { return "foo_event_t"; }
    std::vector<class_id_t> parent() const
    { 
        std::vector<class_id_t> r;
        r.push_back("foo_base_event_t");
        return r;
    }
};

struct foo_event_listener_t : listener_t {
    static std::vector<class_id_t> relevant_ids()
    {
        std::vector<class_id_t> r;
        r.push_back("foo_event_t");
        return r;
    }

    foo_event_listener_t()
    : listener_t (relevant_ids())
    { }

    void notify(event_t const& e)
    {
        std::cout << "foo_event_listener_t::notify() with " << typeid(e).name() << " " << (void*)&e << "\n";
    }
};

struct foo_base_event_listener_t : listener_t {
    static std::vector<class_id_t> relevant_ids()
    {
        std::vector<class_id_t> r;
        r.push_back("foo_base_event_t");
        return r;
    }

    foo_base_event_listener_t()
    : listener_t (relevant_ids())
    { }

    void notify(event_t const& e)
    {
        std::cout << "foo_base_event_listener_t::notify()" << typeid(e).name() << " " << (void*)&e << "\n";
    }
};

int main()
{
    type_registry_t reg;

    reg.register_type("event_t", std::vector<class_id_t>());
    reg.register_type("foo_base_event_t", std::vector<class_id_t>(1, "event_t"));
    reg.register_type("foo_event_t", std::vector<class_id_t>(1, "foo_base_event_t"));

    dispatcher_t dispatcher (reg);
    dispatcher.connect(std::shared_ptr<listener_t>(new foo_event_listener_t()));
    dispatcher.connect(std::shared_ptr<listener_t>(new foo_base_event_listener_t()));

    foo_base_event_t foo_base_event;
    dispatcher.signal(foo_base_event);

    foo_event_t foo_event;
    dispatcher.signal(foo_event);


    return 0;
}

您需要使用首选方法向Python公开其中一些内容,以允许注册事件类型。我没有包含错误检查和构造class_id的集合,每次调用listen_for()可能都很慢。