3

Baseから派生した100のクラスがあるとしましょう。これらの派生クラスのそれぞれには、コンパイル時に既知の[0,100)間の一意の識別子があります。

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

私はばかげていますか、それともそれほど多くのスペースを必要としない別のアプローチがありますか?

4

2 に答える 2

1

IDごとに巨大なスイッチケースを用意するのは明らかに良い解決策ではありません。

これは実際には抽象的なファクトリパターンであり、説明したとおりに広く使用されています。ほとんどのプログラマーにはおなじみなので、私はそれに固執します。

バリアントは非常に複雑で、保守が難しいようです。

于 2012-02-23T16:06:57.560 に答える
0

これは、古い無愛想なマクロ機能がタスクを簡素化し、いくつかのエラーを排除できる状況です。

#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
于 2012-02-23T16:32:00.803 に答える