2012-01-02 51 views
6

Code:Làm thế nào để tạo một mảng các lớp trong C++?

struct Base { ... }; 

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

Có thể tạo một mảng, mà cho rằng loại struct? mẫu/Kết quả mong đợi:

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

Mục đích của việc này là sau, tôi muốn tạo một đối tượng với một lớp ngẫu nhiên lấy từ mảng.

+0

bạn có ý nghĩa như thế: 'vector v;' –

+3

Bạn có muốn một mảng các loại bản thân? Hoặc một mảng các đối tượng của các loại? –

+1

@BenjaminLindley: Rõ ràng là anh ta muốn một loạt các loại. Tuy nhiên, việc sử dụng 'Base' làm loại mục mảng là gây hiểu lầm. –

Trả lời

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

Nếu bạn muốn bảo vệ người sáng tạo đối tượng, hãy chuyển người tạo tĩnh sang phần riêng tư/được bảo vệ và biến lớp này thành bạn bè thành lớp người sáng tạo bên ngoài cụ thể. Điều này có thể hữu ích bất cứ khi nào quá trình tạo phức tạp và dễ xảy ra lỗi. Người sáng tạo bên ngoài có toàn bộ kiến ​​thức về cách tạo các đối tượng của lớp này một cách chính xác, vì vậy người dùng cuối không bao giờ thất bại ở đây. – rzur2004

+0

tôi không recomment bằng cách sử dụng RTTI trừ khi Bạn biết nền tảng cụ thể, và mỗi mô-đun (DLL, SO, LIB ....) có đúng tùy chọn biên dịch và liên kết. Một số trình biên dịch cũ hơn có thể có vấn đề với RTTI với không gian tên và đăng ký mô-đun chéo cho đặc biệt nhà máy như vậy khi chúng tôi cố gắng đăng ký các lớp mẫu. Nói chung RTTI là tuần, cố gắng không sử dụng nó, vì RTTI có thể bị vô hiệu hóa ở cấu hình xây dựng, và nothig sẽ chạy. – rzur2004

+0

Ok tôi dùng thử, thx – justi

0

Tôi không hiểu câu hỏi. Bạn có yêu cầu một mảng có thể chứa các loại cá thể khác nhau cùng một lúc không? Đó là có thể sử dụng đa hình, tất nhiên. Hoặc bạn đang cố gắng để có được một mảng các loại (như phản ánh)? Điều đó sẽ có thể sử dụng thông tin kiểu RTTI hoặc Qt (như một ví dụ), nhưng tôi chưa bao giờ làm điều đó.

+0

Yêu cầu làm rõ đi như ý kiến, không phải là câu trả lời. –

5

Nếu trình biên dịch của bạn hỗ trợ RTTI, bạn có thể làm điều gì đó như:

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

Tuy nhiên, bạn sẽ không thể để nhanh chóng một lớp chỉ type_info của nó sử dụng. factory pattern có thể là câu trả lời tốt hơn cho vấn đề gốc của bạn.

Cập nhật: Kể từ type_info trường hợp không thể sao chép (copy constructor của họ và toán tử gán là private), và mảng tài liệu tham khảo là bất hợp pháp, con trỏ liên tục phải được sử dụng trong ví dụ trên.

5

Bạn có thể tạo một mảng các hàm, mỗi hàm trả về một con trỏ cơ sở (hoặc con trỏ thông minh) mà mỗi điểm đến các đối tượng của các lớp dẫn xuất khác nhau của bạn. ví dụ.

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](); 
} 

Đây là nó trong hành động: http://ideone.com/dg4uq

+1

Hm, thú vị .. – justi

+0

Tôi thử Ví dụ của bạn, nhưng trong trình biên dịch của tôi không hoạt động: là một số vấn đề với unique_ptr – justi

+1

@justi: Hãy thử bao gồm tiêu đề ' '. Tôi nên làm điều đó anyway, nó chỉ xảy ra rằng một trong các tiêu đề khác dường như mang nó vào. Nếu điều đó không làm việc, những gì trình biên dịch (và phiên bản) bạn đang sử dụng? Đó là một tính năng C++ 11, vì vậy có thể trình biên dịch của bạn không hỗ trợ nó, hoặc bạn có thể cần thiết lập một số cờ. ví dụ. với g ++, bạn cần '-std = C++ 0x'. Nếu bạn không thể sử dụng C++ 11, băn khoăn không, có các giải pháp khác, nhưng hãy thử điều này trước. –

Các vấn đề liên quan