2012-01-02 10 views
6

コード:C++でクラスの配列を作成するには?

struct Base { ... }; 

struct A : public Base { ... }; 
struct B : public Base { ... }; 
struct C : public Base { ... }; 

は、構造体の種類を保持する配列を作成することは可能ですか? サンプル/期待される結果:

Type inheritedTypesOfStruct[3] = {A, B, C}; 

この目的は、私は後で配列から取り出されたランダムクラスとオブジェクトを作成したいということです。 C++で多型を使用する方法についてhttp://www.java2s.com/Code/Cpp/Class/Objectarraypolymorphism.htm

+0

あなたがそのような意味: 'ベクトル V;' –

+3

はあなたがタイプ自身の配列をしたいですか?または、型のオブジェクトの配列? –

+1

@BenjaminLindley:明らかに彼はタイプの配列を望んでいます。しかし、配列項目の型として 'Base'を使用すると誤解を招きます。 –

答えて

1
#include <cstdlib> 
#include <ctime> 
#include <iostream> 
#include <map> 
#include <vector> 
#include <memory> 

using namespace std; 




// interface 
class Base 
{ 
public: 
    virtual ~Base() { } 
    virtual int getClassId() = 0; 
}; 


// class A relizes interface Base, has ID == 1 (is used in automatic registration to factory) 
class A : public Base 
{ 
public: 
    const static int ID = 1; 
    static Base* CreateInstance() 
    { 
     return new A(); 
    } 

    virtual int getClassId() 
    { 
     return ID; 
    } 

    virtual ~A() { } 
}; 


// class B relizes interface Base, has ID == 2 (is used in automatic registration to factory) 
class B : public Base 
{ 
public: 
    const static int ID = 2; 
    static Base* CreateInstance() 
    { 
     return new B(); 
    } 

    virtual int getClassId() 
    { 
     return ID; 
    } 

    virtual ~B() { } 
}; 



// this is the objects factory, with registration only (unregister s not allowed) 
class ObjectFactory 
{ 
    ObjectFactory() { } 
    ObjectFactory(ObjectFactory&) { } 
public: 
    virtual ~ObjectFactory() { } 
    static ObjectFactory& instance() 
    { 
     static ObjectFactory objectFactory; 

     return objectFactory; 
    } 

    typedef Base* (*Creator)(); 

    void registerCreator(int id, Creator creator) 
    { 
     registry[id] = creator; 
    } 

    Base* CreateById(int id) 
    { 
     return registry[id](); 
    } 

private: 
    map<int, Creator> registry; 
}; 


// this template class is used for automatic registration of object's creators 
template <class T> 
struct RegisterToFactory 
{ 
    RegisterToFactory(ObjectFactory& factory) 
    { 
     factory.registerCreator(T::ID, &T::CreateInstance); 
    } 
}; 


namespace 
{ 
    // automaticaly register creators for each class 
    RegisterToFactory<A> autoregisterACreator(ObjectFactory::instance()); 
    RegisterToFactory<B> autoregisterBCreator(ObjectFactory::instance()); 
} 




// lets this this solution 
int main(int argc, char *argv[]) 
{ 
    vector<int> ids; 

    ids.push_back(static_cast<int>(A::ID)); 
    ids.push_back(static_cast<int>(B::ID)); 

    srand(time(0)); 

    for (int i = 0; i < 20; ++i) 
    { 
     int randomClasssId = ids[rand() % ids.size()]; 
     auto_ptr<Base> testObject(ObjectFactory::instance().CreateById(randomClasssId)); 
     cout << "Object of classId = " << testObject->getClassId() << " has been produced by factory." << endl; 
    } 


    system("PAUSE"); 
    return EXIT_SUCCESS; 
} 
+0

オブジェクト作成者を保護したい場合は、静的作成者をprivate/protectedセクションに移動し、このクラスを具体的な外部作成者クラスと友人にします。これは、作成プロセスが複雑でエラーが発生しやすいときに便利です。外部作成者は、このクラスのオブジェクトを正しくインスタンス化する方法を完全に理解しているため、エンドユーザーはここで失敗することはありません。 – rzur2004

+0

具体的なプラットフォームを知っておらず、すべてのモジュール(DLL、SO、LIB ....)が厳密に同じコンパイルとリンクオプションを持っていない限り、私はRTTIを使って推薦しません。古いクラスのコンパイラの中には、テンプレートクラスを登録しようとしたときにRTTIにネームスペースやモジュール間での登録に問題があるものがあります。一般的に、RTTIは週になっていますが、RTTIがビルド構成で無効になる可能性があり、nothigが実行されるため、使用しないでください。 – rzur2004

+0

オクラホマ、私はそれを試してみよう – justi

-1

現在地見ることができます。

+0

質問は多型に関するものではなく、リンクは回答ではありません –

0

私は質問をしません。同時に異なるタイプのインスタンスを保持できる配列を要求していますか?それはもちろん、多態性を使って可能です。または、あなたはリフレクションのような型の配列を取得しようとしていますか?それはRTTIやQtタイプの情報(例として)を使って可能ですが、決してそうしませんでした。

+0

明確化のリクエストは回答ではなくコメントとして扱います。 –

5

コンパイラがRTTIをサポートしている場合は、あなたのような何かを行うことができます。

const type_info *inheritedTypesOfStruct[3] = { 
    &typeid(A), &typeid(B), &typeid(C) 
}; 

をただし、あなただけのtype_infoを使用してクラスをインスタンス化することはできません。​​は、根本的な問題に対するより良い答えかもしれません。

更新:type_infoインスタンスは(彼らのコピーコンストラクタと代入演算子はprivateある)コピーすることができず、参照の配列が違法であるので、一定のポインタは、上記の例で使用しなければなりません。

5

各派生クラスのオブジェクトを指す基本ポインタ(またはスマートポインタ)を返す関数の配列を作成できます。例えば

typedef std::unique_ptr<Base> base_ptr; 

template<typename Derived> 
base_ptr CreateObject() 
{ 
    return base_ptr(new Derived); 
} 

int main() 
{ 
    std::function<base_ptr(void)> f[3] = { 
     CreateObject<A>, CreateObject<B>, CreateObject<C> 
    }; 

    base_ptr arr[10]; 
    for (int i=0; i<10; ++i) 
     arr[i] = f[rand()%3](); 
} 

ここでは、アクションである:http://ideone.com/dg4uq

+1

うーん、興味深い.. – justi

+0

私はあなたの例を試してみるが、私のコンパイラでは動作しません:unique_ptrにいくつかの問題があります – justi

+1

@justi:ヘッダ ' 'を含めてみてください。とにかくそれをやったのですが、他のヘッダーの1つが明らかにそれを持ってきたことが起こっただけです。それがうまくいかない場合は、どのコンパイラ(とバージョン)を使用していますか?これはC++ 11の機能なので、コンパイラでサポートされていないか、フラグをいくつか設定する必要があるかもしれません。例えばg ++では '-std = C++ 0x'が必要です。 C++ 11を使用できない場合は、他の解決策もありますが、まずこれを試してみましょう。 –

関連する問題