soulfreshner
soulfreshner

Reputation: 366

C++ Polymorphism and the new keyword

Is there some way to allocate memory depending on the type of pointer passed?

Here is my problem: I have a 'bouncyball' and 'hero' class both inheriting from 'Actor'. To add a bouncyball, I call:

_actors.push_back(new Bouncyball());

For a hero, it would be:

_actors.push_back(new Hero());

Since _actors is a vector of Actor pointers, it works because of polymorphism. But I want to write a generic method to add new actors to my scene:

unsigned Scene::addActor(Actor * actor){
    this->_actors.push_back(new [something]);
}

Because the parameter can be any derivative of Actor, I don't know what to allocate memory for... I can work around this with a case statement, but what if I derive other Actors later on?

Upvotes: 0

Views: 1150

Answers (3)

moshbear
moshbear

Reputation: 3322

Why not create a pv class Clonable:

template <typename T>
struct Clonable {
    virtual smart_ptr<T> clone() const = 0;
}

for smart_ptr being std::shared_ptr, std::unique_ptr, boost::shared_ptr, etc. The point is to refcount the pointer to avoid use of manual deletes, except when writing a custom Deleter.

Then define Actor as:

 class Actor : ..., public Clonable<Actor> {
 ...
 public:
     ...
     virtual smart_ptr<T> clone() const { return 0; }
     ...
 ...
}

Then, for T : public Actor,

scene.addActor((T()).clone());

Upvotes: 0

Dan O
Dan O

Reputation: 4450

Nawaz's solution is fine, but an alternative is a template member function:

template<typename T>
unsigned Scene::addActor()
{
   _actors.push_back(new T());
}

And then in the client code:

scene.addActor<Hero>();

It's worth noting that the template member function will need to be implemented in a header or file included by a header (such as a .inl). If you implement it directly in the class body you shouldn't write Scene:: in front of addActor().

One advantage of this method is that clients are not calling new. It's generally 'bad' if code is calling new, but isn't calling delete, and in this case delete would presumably be called by the Scene class later. This also creates a pinch point if a custom allocator needs to be used for performance reasons.

Upvotes: 2

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361352

What is wrong with this:

unsigned Scene::addActor(Actor * actor){
    this->_actors.push_back(actor);
    //what do you want to return? why not make return type as void?
}

Isn't it actor which you want to add to _actors?

And you can call addActor() as:

scene.addActor(new Bouncyball());
scene.addActor(new Hero());

Make sure that you declare the destructor of Actor as virtual, as most likely you would want to delete derived class objects through the pointer of base type (which is Actor).

Upvotes: 3

Related Questions