C ++ RTTI注册表模式

时间:2015-07-07 01:16:41

标签: c++ c++11 polymorphism rtti

我有兴趣了解更多有关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();
}

2 个答案:

答案 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;
};

Live example