在运行时将ID解析为派生类型

Resolving an ID to a derived type at runtime

本文关键字:派生 类型 运行时 ID      更新时间:2023-10-16

假设我有100个从Base派生的类。这些派生类中的每一个都有一个在[0100)之间的唯一标识符,在编译时已知

我有一个函数,它接受一个ID,并需要返回一个新分配的带有该ID的派生类实例。

Base* CreateDerived(uint32_t id) {
    return new Derived...();
}

显然,为每个ID都设置一个巨大的交换机案例不是一个好的解决方案。下面提供了我能想到的最佳解决方案的示例,但我觉得有一种方法可以做到这一点,而不需要vtable带来的开销。

struct RegisteredClass {
    static RegisteredClass* ClassTable[MAX_DERIVED_CLASSES];
    static Base* CreateDerived(int ID) { return ClassTable[ID]->Create(); }
    RegisteredClass(int ID) { ClassTable[ID] = this; }
    virtual Base* Create() = 0;
};
template<typename T, int ID>
struct Register : RegisteredClass {
    Register() : RegisteredClass(ID) { }
    virtual Base* Create() { return new T; }
};
class Derived34 : Base {
    static Register<Derived34, 34> _register;
};

我是在傻吗,还是有其他不需要那么多空间的方法?

显然,每个都有一个巨大的开关箱不是一个好的解决方案ID。

这实际上是抽象的工厂模式,正如你所描述的那样,它被广泛使用。我会坚持它,因为它对大多数程序员来说都很熟悉。

您的变体似乎过于复杂,难以维护。

在这种情况下,旧的crusty宏功能可以简化任务并消除一些错误。

#define CASE(n) case n: return new Derived##n
Base* CreateDerived(uint32_t id)
{
    switch(id)
    {
        CASE(1);
        CASE(2);
        CASE(3);
        // ...
        default:
            throw std::logic_error("Unhandled Derived## case");
    }
}
#undef CASE