3

ファクトリーパターンを使用しています。基本的に、コンパイル時にクラスを登録し、マップに格納できます。BaseFactory::createInstance() を使用してインスタンスを返すことができます。

コンパイル時にマップがクラス名をどのように保持しているかわかりません!! 実行時に有効なメモリをコンパイル時にどのように割り当てることができますか?

この場合、すべてのクラスは親クラス Bump_BaseObject から派生します。

//C++ STL used for adding Reflection
#include <string>
#include <map>


class Bump_BaseObject;

/**
 * Derived Base objects creation factory
 */
template<typename T>
Bump_BaseObject* createT(void)
{
#pragma message("createT instantiated")
    return new T();
}

struct BaseFactory {
    typedef std::map<std::string, Bump_BaseObject*(*)()> map_type;

    //return an instance of the class type 's'
    static Bump_BaseObject* createInstance(const std::string& s) {
        map_type::iterator it = getMap()->find(s);
        if(it == getMap()->end())
            return 0;

        //this is where we instatiate and allocate memory for the object(it must NOT have any arguments)
        //we could write a variant that accepts args, but there is no need.
        return it->second();
    }

    //check if 's' is present in the map of registered types
    static bool checkIfRegisteredType(const std::string& s) {
        map_type::iterator it = getMap()->find(s);
        if(it == getMap()->end())
            return false;

        return true;
    }

protected:
    static map_type* getMap() {
        // never delete'ed. (exist until program termination)
        // because we can't guarantee correct destruction order
        if(!objectMap) { objectMap = new map_type; }
        return objectMap;
    }

private:
    static map_type * objectMap;
};

#define VALUE_TO_STRING(x) #x

template<typename T>
struct DerivedRegister : BaseFactory {
    DerivedRegister(const std::string& s) {


#pragma message("Type registered")
        getMap()->insert(std::pair<std::string, Bump_BaseObject*(*)()>(s, &createT<T>));
    }
};

また、登録時にクラス名を出力する方法はありますか?

4

1 に答える 1

6

あなたのコードは完全に混乱していると思います。プリプロセッサ ディレクティブと奇妙な継承パターンが混在しています。それを修正しようとする代わりに、一般的な自己登録ファクトリ フレームワーク (登録が発生すると出力される) を提示したいと思います。

すべてのグローバル初期化は、動的初期化フェーズmain()、つまり実行時にが呼び出される直前に行われることに注意してください。

ベース.hpp:

#include <unordered_map>
#include <string>

class Base
{
public:
    typedef Base * (*base_creator_fn)();
    typedef std::unordered_map<std::string, base_creator_fn> registry_map;

    virtual ~Base() = default;

    static registry_map & registry();
    static Base * instantiate(std::string const & name);
};

struct Registrar
{
    Registrar(std::string name, Base::base_creator_fn func);
};

Base.cpp:

#include "Base.hpp"
#include <iostream>

registry_map & Base::registry()
{
    static registry_map impl;
    return impl;
}

Base * Base::instantiate(std::string const & name)
{
    auto it = Base::registry().find(name);
    return it == Base::registry().end() ? nullptr : (it->second)();
}

Registrar::Registrar(std::string name, Base::base_creator_fn func)
{
    Base::registry()[name] = func;
    std::cout << "Registering class '" << name << "'\n";
}

使用例

例.hpp:

#include "Base.hpp"

class DerivedExample : public Base
{
    static Registrar registrar;
public:
    static Base * create() { return new DerivedExample; }
    // ...
};

例.cpp:

#include "Example.hpp"

Registrar DerivedExample::registrar("DerivedExample", DerivedExample::create);

メイン.cpp

#include "Example.hpp"

int main()
{
    Base * p = Base::instantiate("DerivedExample");
    Base * q = Base::instantiate("AnotherExample");
}

ここで重要なのは、各派生クラスには静的Registrarメンバーがあり、プログラムの動的初期化フェーズ中に (指定されていない順序で) 初期化され、各コンストラクターがレジストリ マップへの実際の挿入と出力を実行することです。ログメッセージ。


(最新の C++ コンパイラがない場合は、古い C++98 スタイルの構文を使用する必要があります:)

virtual ~Base() { }   //  no "= default"

Base::registry_map::const_iterator it = Base::registry().find(name); // no "auto"
于 2012-05-20T20:58:25.920 に答える