2

さまざまな継承された型を保持し、それらをインスタンス化するコンテナ(std :: vectorとしましょう)が必要です。つまり、クラスのベクトル->オブジェクトのベクトルです。

例えば:

class A{};

class B: public class A
{};

class C: public class A
{};

void main()
{
    std::vector<of inherited A types> typesVec;
    std::vector<A*> objectsVec;

    typesVec.push_back(class B);
    typesVec.push_back(class C);

    for (int i = 0; i < typesVec.size(); i++)
    {
        A* pA = new typesVec.at(i);
        objectsVec.push_back(pA);
    }

}

前もって感謝します..

4

4 に答える 4

6

これは C++ では不可能です (少なくとも直接的には不可能です)。これは、リフレクションのある言語で発生することがわかりますが、C++ ではありません。

代わりにできることは、指定されたタイプのオブジェクトを作成するファクトリまたは単にメソッドを作成することです。

型のベクトルを使用する代わりに、オブジェクト ジェネレーターのベクトルを使用します (十分に近いでしょう?)。

class A{};

class B: public class A
{};

class C: public class A
{};

struct AFactory
{
    virtual A* create() { return new A; }
};
struct BFactory : AFactory
{

    virtual A* create() { return new B; }
};
struct CFactory : AFactory
{

    virtual A* create() { return new C; }
};

//...

typesVec.push_back(new BFactory);
typesVec.push_back(new CFactory);

for (int i = 0; i < typesVec.size(); i++)
{
    A* pA = typesVec.at(i)->create();
    objectsVec.push_back(pA);
}
于 2012-10-10T11:42:10.600 に答える
1

テンプレートを使用した再利用可能なアプローチがあります。これは、次のようなコードを記述できるinstallおよびメソッドに付属する派生型のジェネリック ファクトリです。create

int main() {
    TypeVector<Base> t;
    t.install<Foo>("Foo");
    t.install<Bar>("Bar");

    t.create("Foo")->hello();
}

これはスケッチの実装であることに注意してください。現実の世界では、別のテンプレート パラメーターを提供して、基になるコンテナーの型を指定する場合があります (いくつかの型でvectorは、おそらく よりも効率的ですset)。

型ベクトルは次のとおりです。

    template <typename Base>
    class Creator;

    template <typename Base>
    class TypeVector {
    public:
        template <typename Derived>
        void install (std::string const &name) ;

        std::shared_ptr<Base> create (std::string const &name) const;

    private:
        struct Meta {
            Meta(std::shared_ptr<Creator<Base>> creator, std::string const &name)
                : creator(creator), name(name) {}

            std::shared_ptr<Creator<Base>> creator;
            std::string name;
        };

        std::vector<Meta> creators_;
    };

どういうわけか、型を割り当て可能な方法で格納する方法が必要です。のようboost::shared_ptrに行います。これは、抽象基本クラスとテンプレート派生クラスを組み合わせたものです。

template <typename Base>
class Creator {
public:
    virtual ~Creator() {}        
    virtual std::shared_ptr<Base> create() const = 0;
};

template <typename Base, typename Derived>
class ConcreteCreator : public Creator<Base> {
public:
    virtual std::shared_ptr<Base> create() const {
        return std::shared_ptr<Base>{new Derived()};
    }
};

「具体的なクリエーター」は、実際のオブジェクトを割り当て、そのベースへのポインターを返すことができます。

最後に、 と の実装を次に示しTypeVector::installますTypeVector::create

template <typename Base>
template <typename Derived>
void
TypeVector<Base>::install (std::string const &name)
{
    creators_.emplace_back(
        std::shared_ptr<Creator<Base>>(new ConcreteCreator<Base, Derived>()),
        name);
}

template <typename Base>
std::shared_ptr<Base> 
TypeVector<Base>::create (std::string const &name) const
{
    for (auto m : creators_) {
        if (name == m.name) return m.creator->create();
    }
    throw std::runtime_error("...");
}

そして最後に、ここにテストがあります:

#include <iostream>
struct Base {
    virtual ~Base() {}
    virtual void hello() const = 0;
};
struct Foo : Base {
    virtual void hello() const { std::cout << "I am a Foo\n"; }
};
struct Bar : Base {
    virtual void hello() const { std::cout << "I am a Bar\n"; }
};

int main() {
    TypeVector<Base> t;
    t.install<Foo>("Foo");
    t.install<Bar>("Bar");

    t.create("Foo")->hello();
}

さらに進んで、次のようなコードに対して任意のコンストラクターを呼び出し可能にすることができます...

...
    Bar(Color, Age, int)
...
t.create("Foo", Color::Red, Age::TooOld, 42)

...しかし、これには、可変個引数のテンプレート引数リストと、それらをコンストラクター呼び出しに折りたたむ方法をよく理解する必要があります(実行可能であり、実行されていますが、この回答が爆発するでしょう)。

于 2012-10-10T12:25:54.470 に答える
0

Andrei Alesandrescu の本 Modern C++ Design (または彼が本で説明している Loki ライブラリ) と、型リストに関する章を紹介します。typeVec.insert( type )これには、コンパイル時に行う必要があります。

于 2012-10-10T12:10:11.957 に答える
0

簡単なソリューション スケッチ:

C++ 標準では、コンストラクターへの直接呼び出しは提供されていません。そのため、コンストラクターへの関数ポインターを持つことはできません。ただし、次のようなラッパー関数「作成」を使用できます。

template<typename T>
T* create () {
   return (new T();
}

オーバーロードされた create 定義を 1 つの引数、2 つの引数、... に指定するか、可変個引数テンプレートを使用してみてください。または、必要なタイプがすでにわかっている場合は、作成関数を具体的に作成できます。次に、作成関数への関数ポインターを設定できます。

&create<TheType>

ただし、この関数のシグネチャは使用する型に依存することに注意してください。ただし、テンプレート化された型の typdef、型ポインターの typedef、および functor としての create 関数を含む構造体を作成できますoperator()

したがって、2 つのベクトルを作成できます。1 つは create 関数への関数ポインター用、または前述の構造体用、もう 1 つは実際のオブジェクト用です。継承された型のみがある場合、継承された型 B、C、... ごとに関数A* createB() { return new B(); }、 、... を定義し、これらの作成関数へのポインタのベクトルと A の 2 番目のベクトルを持つことができる場合があります。A* createC() { return new C(); }ポインター。

于 2012-10-10T11:54:45.187 に答える