Sean
Sean

Reputation: 75

Method to create inherited object

Quick question. I've got a bunch of inherited classes like so:

Object_____
  |       |
Actor    Item
  |
  |_______
Human  Animal

I also have a class called Room, defined like so:

class Room 
{
    Object * addObject (unsigned long _UID, string _name);
    map<int, Object *> objects; // A map containing the Objects within the room
}

What I'd like to do is make the function addObject() able to instantiate any type of the Object classes, something like Room.addObject(Object::Actor::Human), which would then add a Human Object to my list of Objects in the Room. They all have the same constructor arguments, if that helps. Is there any way to do this in C++?

Upvotes: 0

Views: 88

Answers (2)

Chris Olsen
Chris Olsen

Reputation: 3511

I think what you're looking for is a factory pattern for C++. While there are many ways of implementing factories in C++, as far as I know there isn't a standard.

I think simple is often best, so here is an example of a very simplistic object factory using your example code:

#include <memory>
#include <string>
#include <map>
using namespace std;

// Stub class definitions
class Object { public: Object() {} ~Object() {} };
class Actor : public Object { public: Actor() {} ~Actor() {} };
class Human : public Actor { public: Human() {} ~Human() {} };
class Animal : public Actor { public: Animal() {} ~Animal() {} };
class Item : public Object { public: Item() {} ~Item() {} };

class ObjectFactory
{
public:
    static shared_ptr<Object> create_object(string name);
};

shared_ptr<Object> ObjectFactory::create_object(string name)
{
    if (name == "Human")
        return shared_ptr<Object>(new Human());
    if (name == "Actor")
        return shared_ptr<Object>(new Actor());
    if (name == "Animal")
        return shared_ptr<Object>(new Animal());
    if (name == "Item")
        return shared_ptr<Object>(new Item());
    throw "unknown object type";
}

class Room 
{
public:
    shared_ptr<Object> addObject (unsigned long _UID, string _name);
    map<int, shared_ptr<Object>> objects; // A map containing the Objects within the room
};

shared_ptr<Object> Room::addObject(unsigned long _UID, string _name)
{
    shared_ptr<Object> object = ObjectFactory::create_object(_name);
    objects[_UID] = object; // not sure if this is what you intended to use _UID for...
    return object;
}

int main()
{
    Room room;
    room.addObject(1, "Actor");
    return 0;
}

Note that this could be done using Object * in place of shared_ptr<Object> too, you just wouldn't have the automatic reference counting/deleting and would have to keep track of the objects yourself (not too hard considering they're stored in a map).

Upvotes: 1

Charlie
Charlie

Reputation: 1592

template<typename T> Object* addObject( ... ) {
  Object* myobject = new T(...);
  objects.insert({someint, myobject});
}

...
myroom.addObject<Human>(...);

You'll need to change your map from storing objects to storing pointers to objects, and figure out what the owner of the objects is so that you clean them up. (might be useful to make your map store unique_ptrs or shared_ptrs.

Upvotes: 1

Related Questions