假设我有一系列的类,它们都实现相同的接口(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/