2012-01-02 79 views
6

代碼:如何在C++中創建一個類的數組?

struct Base { ... }; 

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

是否有可能創建一個數組,即認爲結構的類型? 樣品/預期的結果:

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

這樣做的目的是,我以後要與來自陣列取回的隨機類創建對象。

+0

你的意思是這樣的:'向量 V;' – 2012-01-02 15:44:11

+3

你想要的類型本身的數組?或者這些類型的對象數組? – 2012-01-02 15:46:38

+1

@ BenjaminLindley:顯然他想要一個類型的數組。然而,使用'Base'作爲數組項目類型是有誤導性的。 – 2012-01-02 15:47:34

回答

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

如果您想保護對象創建者,請將靜態創建者移動到私有/受保護的部分,並將此類朋友帶到具體的外部創建者類。只要創建過程複雜且容易出錯,這可能是有用的。外部創建者完全知道如何正確實例化這個類的對象,所以最終用戶永遠不會在這裏失敗。 – rzur2004 2012-01-02 18:36:35

+0

我不會推薦使用RTTI,除非你知道具體的平臺,並且每個模塊(DLL,SO,LIB ....)都有嚴格的相同的編譯和鏈接選項。當我們嘗試註冊模板類時,一些較早的編譯器可能會遇到與RTTI有關的問題,其中名稱空間和交叉模塊註冊到這樣的工廠尤其如此。通常RTTI是一週,儘量不要使用它,因爲RTTI可能在構建配置時被禁用,並且不會運行。 – rzur2004 2012-01-02 18:45:52

+0

好吧,我嘗試一下,thx – justi 2012-01-02 20:13:23

0

我不明白這個問題。你是否要求一個可以同時容納不同類型實例的數組?當然,這可以使用多態。還是你想獲得一個類型數組(如反射)?這可以使用RTTI或Qt類型信息(作爲例子),但我從來沒有這樣做。

+0

要求澄清的內容以評論形式發佈,而不是答案。 – 2012-01-02 16:22:36

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 2012-01-02 16:07:07

+0

我嘗試你的例子,但在我的編譯器不工作:是unique_ptr – justi 2012-01-02 16:51:18

+1

@justi一些問題:嘗試包括頭''。無論如何,我應該這樣做,只是其中一個頭顯然帶來了它。如果這不起作用,你使用什麼編譯器(和版本)?這是一個C++ 11功能,所以有可能你的編譯器不支持它,或者你可能需要設置一些標誌。例如用g ++,你需要'-std = C++ 0x'。如果你不能使用C++ 11,不要擔心,還有其他的解決方案,但我們先來試一試。 – 2012-01-02 16:56:12

相關問題