我有兴趣了解更多有关RTTI在C ++中的优点和局限性。假设我有以下情况:
class C {};
class C0 : public C {};
class C1 : public C {};
...
void print(int id, C* c) {
if (id == 0) dynamic_cast<C0 *>(c)->print();
else if (id == 1) dynamic_cast<C0 *>(c)->print();
...
}
是否可以使用注册表模式实现上述示例?例如,使用以下内容:
map<int, ?> registry;
void print(int id, C* c) {
registry[id](c)->print();
}
答案 0 :(得分:3)
只需将print
作为虚函数即可轻松解决。然后你可以简单地:
void print(C* c)
{
c->print();
}
它会为所有派生类做正确的事。
但是如果你想让print
非虚拟,那么当你认识到registry[id](c)->print();
之类的东西可以起作用的问题时。映射的值类型是编译时的事实,但是您希望行为中存在运行时差异。
好吧,我可以想到一种方法来做到这一点......通过使用虚函数。您需要创建一个作为C
包装器的类,其派生版本与从C
派生的类型相匹配。一些模板使用可能会使这一点有点像处理。然后根据指向基类的指针声明映射,但是通过派生的包装器填充。
但最终需要更多的复杂性并且没有提供比仅仅使print
本身虚拟化所能实现的更多的好处。
答案 1 :(得分:1)
虽然使用多态和虚方法似乎更合适,但您可以使用以下内容根据id
class PrintCaller
{
public:
template <typename T>
std::size_t register_class()
{
m.push_back([](C* c) {
auto* p = dynamic_cast<T*>(c);
if (p) {
p->print();
} else {
throw std::runtime_error("Incorrect type");
}
});
return m.size() - 1;
}
void print(std::size_t id, C* c) const {
if (id < m.size()) {
m[id](c);
} else {
throw std::runtime_error("invalid id");
}
}
private:
std::vector<std::function<void(C*)>> m;
};