假设我有一系列的类,它们都实现相同的接口(interface),也许用于调度:

class Foo : public IScheduler {
public:
    Foo (Descriptor d) : IScheduler (d) {}
    /* methods */
};

class Bar : public IScheduler {
public:
    Bar (Descriptor d) : IScheduler (d) {}
    /* methods */
};

现在假设我有一个Scheduler类,您可以要求为给定的描述符启动一个IScheduler派生的类。如果已经存在,将为您提供引用。如果不存在,则会创建一个新的。

一种假设的调用将是这样的:
Foo & foo = scheduler->findOrCreate<Foo>(descriptor);

要实现该功能,需要将其键(描述符,RTTI)映射到基类指针的映射。然后,您必须dynamic_cast。我猜大概是这样:
template<class ItemType>
ItemType & Scheduler::findOrCreate(Descriptor d)
{
    auto it = _map.find(SchedulerKey (d, typeid(ItemType)));
    if (it == _map.end()) {
        ItemType * newItem = new ItemType (d);
        _map[SchedulerKey (d, typeid(ItemType))] = newItem;
        return *newItem;
    }
    ItemType * existingItem = dynamic_cast<ItemType>(it->second);
    assert(existingItem != nullptr);
    return *existingItem;
}

想知道是否有人可以在不依赖RTTI的情况下获得类似的结果。也许每种计划项目类型都可以拥有自己的 map 实例的方式?设计模式,还是...?

最佳答案

函数或类静态成员的地址保证是唯一的(就<而言),因此您可以将这样的地址用作键。

template <typename T>
struct Id { static void Addressed(); };

template <typename ItemType>
ItemType const& Scheduler::Get(Descriptor d) {
    using Identifier = std::pair<Descriptor, void(*)()>;

    Identifier const key = std::make_pair(d, &Id<ItemType>::Addressed);

    IScheduler*& s = _map[key];

    if (s == nullptr) { s = new ItemType{d}; }

    return static_cast<ItemType&>(*s);
}

请注意,使用operator[]可以避免重复查找并简化函数体。

关于c++ - 不使用RTTI缓存不同派生类型的设计模式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19597838/

10-11 18:45