2

オブジェクトを動的に作成するためにクラス ファクトリを使用しています。シンプルにするためにこの回答を使用しました(そしてQtを使用しているため)。

しかし、コンストラクターに引数を追加する必要があることに気付きました

Item(bool newItem /* = true*/);

それ以外の

Item();

参照された回答のコードの場合:

template <typename T>
class ClassFactory
{
public:
    template <typename TDerived>
    void registerType(QString shape)
    {
        _createFuncs[shape] = &createFunc<TDerived>;
    }    
    T* create(QString shape)
    {
        typename QMap<QString, PCreateFunc>::const_iterator it = _createFuncs.find(shape);
        if (it != _createFuncs.end())
        {
            return it.value()();
        }
        return NULL;
    }    
private:
    template <typename TDerived>
    static T* createFunc()
    {
        return new TDerived();
    }
    typedef T* (*PCreateFunc)();
    QMap<QString, PCreateFunc> _createFuncs;
};

クラスを登録しました

classFactory.registerType <Type1_Item> ("type1");

必要に応じて、私は電話しました

Item* item = classFactory.create("type1");

コンストラクターの引数を表すために、クラス ファクトリに追加の引数を追加しようとしていますが、私の試みはすべてエラーになります。

なぜ私はそれが必要なのですか: 単純なケース:

  • 新しいオブジェクトを作成 - デフォルトを設定します。特定のオブジェクトでは、ファイルからデータをロードする必要があるため、ファイルを開くダイアログが必要です。

  • オブジェクトの読み込み - ファイル情報を含むオブジェクトのファイル名を含むデータを入力します

「ロード」機能を呼び出すには、オブジェクトが存在している必要があります。つまり、新しいオブジェクトを作成すると、必要がないにもかかわらず、ファイルを開くダイアログが表示されます。

私が見る回避策は、コンストラクターの後にセットアップ関数を配置することです。しかし...つまり、オブジェクトの構築には常に2つの関数呼び出しが必要であり、設計が悪いようです。

そのため、次のような単純な呼び出しを使用してクラスを登録して呼び出す方法を探しています

classFactory.registerType <Type1_Item> ("type1", bool);
Item* item = classFactory.create("type1", true);

それは可能ですか、どうすればできますか?

4

5 に答える 5

3

私が考えることができる 1 つの方法は、引数が正確に一致することを要求することです。まず、 を使用して関数を保存しますboost::any。これは、それらのタイプが異なる可能性があるためです。そのため、異種コンテナーが必要です。

QMap<QString, boost::any> _createFuncs;

私たちのregister関数は、上に格納する特定の関数ポインタを作成しますany:

template <typename TDerived, typename... T>
void registerType(QString shape)
{
    _createFuncs[shape] = &createFunc<TDerived, T...>;
}

ここでcreateFunc追加の引数を取ります:

template <typename TDerived, typename... Args>
static T* createFunc(Args... args)
{
    return new TDerived(args...);
}

重要なのは、私たちが作成側で何をするかです。any特定の型に対して保存した が正しい型であるかどうかを確認する必要があります。

template <typename... Args>
T* create(QString shape, Args... args)
{
    using FPtr = T*(*)(Args...);

    auto it = _createFuncs.find(shape);
    if (it != _createFuncs.end())
    {
        // ok, it points to some any. is it the right any?
        FPtr* fptr = boost::any_cast<FPtr>(&it.value());
        if (fptr) {
            return (*fptr)(args...);
        }

        // alternatively to the above, we can have createFunc
        // throw bad_any_cast if you pass the wrong arguments
        // which could be a loud, explicit failure rather than 
        // a silent one
        return boost::any_cast<FPtr>(it.value())(args...);
    }
    return nullptr;
}

これにより、これが機能します:

classFactory.registerType<Item, bool>("type1");
                              ^^^^^^
                              arg list

Item* item = classFactory.create("type1", true);
Item* item2 = classFactory.create<bool>("type1", 1);

ただし、 は ではなく を受け取るため、これは失敗anyboolますint

Item* item3 = classFactory.create("type1", 1);
于 2015-05-11T18:19:05.033 に答える
1

この修正版を使用できます

template <typename T, typename ... Ts>
class ClassFactory
{
public:
    template <typename TDerived>
    void registerType(QString shape)
    {
        _createFuncs[shape] = &createFunc<TDerived>;
    }    
    T* create(QString shape, Ts... args)
    {
        typename QMap<QString, PCreateFunc>::const_iterator it = _createFuncs.find(shape);
        if (it != _createFuncs.end())
        {
            return it.value()(args...);
        }
        return nullptr;
    }    
private:
    template <typename TDerived>
    static T* createFunc(Ts... args)
    {
        return new TDerived(args);
    }
    typedef T* (*PCreateFunc)(Ts...);
    QMap<QString, PCreateFunc> _createFuncs;
};

そしてそれを使う

ClassFactory<Item, bool> classFactory;
classFactory.registerType <Type1_Item> ("type1");

Item* item = classFactory.create("type1", true);
于 2015-05-11T18:28:08.947 に答える
0

すべてのオブジェクトが同じパラメーター タイプ (ここでは bool) を持っている場合は、create 関数を次のように変更します。

T* create(QString shape, bool param)   //modified
{
    typename QMap<QString, PCreateFunc>::const_iterator it = _createFuncs.find(shape);
    if (it != _createFuncs.end())
    {
        return it.value()(param);  //modified
    }
    return NULL;
}    

createFunc も変更します。

static T* createFunc(bool param)
{
    return new TDerived(param);
}
typedef T* (*PCreateFunc)(bool);
于 2015-05-11T18:13:09.687 に答える
-1

C++11 パラメータ パックを使用してこれを実行しました。

// pack.cc
#include <utility>

template<class T, typename... P>
T * create(P&&... params)
{
    return new T(std::forward<P>(params)...);
}


class X
{
public:
    X() {}
};

class Y
{
public:
    Y(int) {}
};

int main()
{
    X * x = create<X>();
    Y * y = create<Y>(1);

    delete x;
    delete y;
}

この例をコンパイルしますg++ -std=c++11 -o pack pack.cc

于 2015-05-11T18:38:26.663 に答える