7

Code:

struct Base { ... };

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

Is it possible to create an array, that holds that types of struct? sample/expected result:

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

The purpose of this is that I later want to create an object with a random class retrieved from the array.

13
  • you mean like that: vector<Base> v; Commented Jan 2, 2012 at 15:44
  • 3
    Do you want an array of the types themselves? Or an array of objects of the types? Commented Jan 2, 2012 at 15:46
  • 1
    @BenjaminLindley: Obviously he wants an array of types. The usage of Base as the array item type is misleading, however. Commented Jan 2, 2012 at 15:47
  • 1
    An array of types. I need that, because I'm going to create obj/struct of random type in future. Commented Jan 2, 2012 at 15:49
  • 2
    @NiklasBaumstark: It's not obvious to me. A lot of people on here don't communicate their intentions effectively, either because they're not fluent in programming terminology, or they're not fluent in English. Commented Jan 2, 2012 at 15:49

5 Answers 5

6

You could create an array of functions, each of which returns a base pointer(or smart pointer) that each point to objects of your various derived classes. e.g.

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

Here it is in action: http://ideone.com/dg4uq

Sign up to request clarification or add additional context in comments.

6 Comments

I try Your example, but in my compiler doesn't work: is some problem with unique_ptr
@justi: Try including the header <functional>. I should have done that anyway, it just happened that one of the other headers apparently brought it in. If that doesn't work, what compiler(and version) are you using? It's a C++11 feature, so it's possible that either your compiler doesn't support it, or you may need to set some flags. e.g. with g++, you need -std=c++0x. If you can't use c++11, fret not, there are other solutions, but let's try this first.
I have default DevCpp environment. I add the header but no results. Adding to compiler -std=c++0x with no positive results.
I'm not sure what compiler DevCpp uses, and unfortunately, I don't have time to investigate it right now. Try to get a modern compiler. I know for sure that both Visual C++ 2010 and MinGW support the code above out of the box. Try to get one of those. I'll be back later to check up.
Unfortunately, The use of DevCpp has been imposed from above. Thx for Your replies.
|
6

If your compiler supports RTTI, you can do something like:

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

However, you won't be able to instantiate a class using only its type_info. The factory pattern might be a better answer to your root problem.

Update: Since type_info instances cannot be copied (their copy constructor and assignment operator are private), and arrays of references are illegal, constant pointers have to be used in the example above.

Comments

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;
}

2 Comments

If You wanna protect the object creator, move static creator to private/protected section, and make this class friend'ed to concrete external creator class. This may be usefull whenever the creation process is complex, and error prone. The external creator has entire knowledge how to properly instantiate objects of this class, so the end-user never fails in here.
i don't recomment using RTTI unless You know the concrete platform, and every module (DLL, SO, LIB ....) has strictly thesame compile and link option. Some older compilers may have problems with RTTI with namespaces and cross module registrations to such factory especialy when we try to register template classes. In general RTTI is week, try not to use it, because RTTI may be disabled at building configuration, and nothig will run.
0

I don't get the question. Are you asking for an array that can hold different type of instances at the same time? That is possible using polymorphism, of course. Or are you trying to get an array of types (like reflection)? That would be possible using RTTI or Qt type information (as an example), but I never did that.

1 Comment

Requests for clarification go as comments, not as answers.
-1

You can take a look here: http://www.java2s.com/Code/Cpp/Class/Objectarraypolymorphism.htm

on how to use Polymorphism in C++.

1 Comment

Question isn't about polymorphism, and links aren't answers

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.