2012-01-02 100 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