7

大規模な IF/ELSE を回避し、ルックアップ テーブルを使用して文字列を特定のクラスに解決し、インスタンス化する方法を探しています。これらはすべて基本クラスから派生します。このようなことは可能ですか?もしそうなら、どのように?

typedef struct BaseClass
{
} BaseClass;

typedef struct DerivedClassOne : BaseClass
{
} DerivedClassOne;

typedef struct DerivedClassTwo : BaseClass
{
} DerivedClassTwo;

typedef struct
{
    const char *name;
    BaseClass class;
} LookupList;

LookupList list[] = {
    {"ClassOne", DerivedClassOne},
    {"ClassTwo", DerivedClassTwo}
};

BaseClass *InstantiateFromString(char *name)
{
    int i;
    for (i = 0; i < 2; i++)
    {
        if (!strcmp(name, list[i].name))
            return new list[i].class();
    }
}

int main (int argc, char *argv[])
{
    BaseClass *myObjectFromLookup = InstantiateFromString("ClassOne");
}
4

4 に答える 4

5

コンパイラが C++11 と互換性がある場合は、ラムダと を使用して簡単に実行できますstd::map

#include <iostream>
#include <string>
#include <map>
#include <functional>

using namespace std;

struct BaseClass {virtual void foo()=0;};
struct DerivedClass1 : public BaseClass {void foo() {cout << "1" << endl;}};
struct DerivedClass2 : public BaseClass {void foo() {cout << "2" << endl;}};

// Here is the core of the solution: this map of lambdas does all the "magic"
map<string,function<BaseClass*()> > factory {
    {"one", [](){return new DerivedClass1();}}
,   {"two", [](){return new DerivedClass2();}}
};

int main() {
    BaseClass *a = factory["one"](); // Note the function call () at the end
    BaseClass *b = factory["two"]();
    a->foo();
    b->foo();
    delete a;
    delete b;
    return 0;
}

アイデアは、適切なサブクラスを作成する関数を提供するマップを作成することです。

ideone のデモ

于 2013-07-20T13:12:26.007 に答える
3

まず、構文の入門書:

struct Base {
    virtual ~Base() {} // do not forget this if you need polymorphism
};

次に、「ファクトリー」関数:

template <typename T>
std::unique_ptr<Base> makeBase() { return std::unique_ptr<Base>(new T{}); }

この関数の型は次のとおりです。

using BaseMaker = std::unique_ptr<Base>(*)();

そして最後に、それをまとめると:

struct DerivedOne: Base {}; struct DerivedTwo: Base {};

using BaseMakerMap = std::map<std::string, BaseMaker>;

BaseMakerMap const map = { { "DerivedOne", makeBase<DerivedOne> },
                           { "DerivedTwo", makeBase<DerivedTwo> } };

std::unique_ptr<Base> makeFromName(std::string const& n) {
    BaseMakerMap::const_iterator it = map.find(n);

    if (it == map.end()) { return std::unique_ptr<Base>(); } // not found

    BaseMaker maker = it->second;

    return maker();
}
于 2013-07-20T12:57:09.243 に答える
0

このようにリストを初期化することはできません。

typedef struct
{
    const char *name;
    BaseClass class;
} LookupList;

LookupList list[] = {
    {"ClassOne", DerivedClassOne},
    {"ClassTwo", DerivedClassTwo}
};

list.class は BaseClass オブジェクトですが、初期値はクラスである DerivedClassOne です。それは意味がありません。コンパイラ エラーが発生します。

于 2013-07-20T12:37:33.847 に答える