实现具有多态检索的类型映射

时间:2016-10-15 14:46:55

标签: c++

我正在研究一个事件系统,它允许触发器将事件发送到单个处理程序或与给定类型相关联的所有处理程序。前者是基本的地图功能,后者大多符合要求...除非你想要多态行为。

class Parent {};
class Child : public Parent {};    

// ...

Parent p; Child c;
Trigger trigger;
Handler h1(&p), h2(&c);

trigger.sendToType<Child>(Event());  // sends the event to h2; OK
trigger.sendToType<Parent>(Event()); // sends the event to h1 only; NO

处理程序根据它们创建的指针类型进行注册。 h1的“类型”为Parenth2的“类型”为Child。使用调度程序中使用的基本类型id映射(只是映射到Handler*向量的某个与类型相关的整数),在向父项发送时无法向子节点发送事件。

我能想到的唯一解决方案有几个缺点:

  • O(n)搜索发送到某个类型。
  • 必须向代码库添加反射
  • 大量手动设置

理想情况下,我想要一个解决方案,其中开销减少到(每个发送到类型的子节点数+实际类型的1个)查找,但这可能是不可能的。有什么建议吗?

1 个答案:

答案 0 :(得分:1)

最简单的解决方案是使用dynamic_cast。可能它在性能方面不是最优的,但应该比map / hash

更快

Here is implementation - test online

#include <iostream>
#include <string>
#include <vector>

struct Event
{
    std::string what;
};

class Parent
{
public:
    virtual void process(const Event& e)
    {
        std::cout << e.what << "Parent" << std::endl;
    }
};
class Child : public Parent
{
public:
    virtual void process(const Event& e) override
    {
        std::cout << e.what << "Child" << std::endl;
    }
};

template<typename T>
void handler(Parent* obj, const Event& e)
{
    if (T* tmp = dynamic_cast<T*>(obj))
        tmp->process(e);
}

template<typename T, typename PARENT>
std::vector<T*> select_objects(const std::vector<PARENT*>& objects)
{
    std::vector<T*> res;
    for (auto obj : objects)
    {
        if (T* tmp = dynamic_cast<T*>(obj))
            res.push_back(tmp);
    }
    return res;
}

int main()
{
    std::vector<Parent*> objects = {new Parent, new Child};

    Event e{"Hello from "};
    std::cout << "All objects" << std::endl;    
    for (auto p : objects)
        handler<Parent>(p, e);
    std::cout << "Child objects only" << std::endl;    
    for (auto p : objects)
        handler<Child>(p, e);

    // here we can build an index to access objects faster
    std::cout << "Child objects only using select" << std::endl;    
    std::vector<Child*> children = select_objects<Child>(objects);
    for (auto o : children)
        o->process(e);
}

输出:

All objects
Hello from Parent
Hello from Child
Child objects only
Hello from Child
Child objects only using select
Hello from Child

UPDATE:您可以构建一些索引来更快地访问对象