Calling a function on a derived class

Hi there. Maybe I'm going about this the wrong way, but I'm trying to call a function on a derived class that's in a vector of it's base class. I've made the code really simple for illustration purposes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Sprite {
    virtual void update();
}

class Enemy : public Sprite {
    virtual void update();
}

class Player : public Sprite {
    virtual void update();
}

class GameManager {
    vector<Sprite > gameObjects;
}

// my code snippet from my game manager
...
Sprite panel;
Enemy enemy;
Player player;

gameObjects.push_back(panel);
gameObjects.push_back(enemy);
gameObjects.push_back(player);

// Here's the problem:
for (int i = 0; i < gameObjects.size(); ++i) {
     gameObjects[i].update();   // <-- This update calls the Sprite update
}


I want to be able to just call update() on the items in the vector and the derived class update() functions be called. Currently, it always calls the Sprite update, which makes sense, but it's not what I want.

Is there a way to call the derived update function without knowing the type of the derived class?

Thanks!!

Chris
You are encountering what is called "object slicing". The problem in your code is that you are doing a copy assignment of the instance when adding the objects to your container. Because your container is of type Sprite, the Enemy and Player types are casted (implicitly) to this type before getting copied to the vector. When you retrieve this copied instance, it is just a Sprite instance.

In order to avoid the slicing, you can store a container of pointers to the object. Storing pointers will not make a copy of the object, thus the pointers stored will refer to the "un-sliced" object. For example:
1
2
3
4
5
6
7
8
9
10
11
12
vector<Sprite*> gameObjects;
Sprite panel;
Enemy enemy;
Player player;

gameObjects.push_back(&panel);
gameObjects.push_back(&enemy);
gameObjects.push_back(&player);

for (int i = 0; i < gameObjects.size(); ++i) {
     gameObjects[i]->update();
}


That will be better for two reasons: 1. Objects will not get sliced as they are stored in the vector, thus allowing late binding to call virtual methods. 2. No object copies made which makes your stack (or heap) usage low.
Thanks for the reply, Vince. That makes sense, and I considered that. However, I was using the vector<Sprite> to store the instances of the Sprites when I create them so I would need another way to keep the objects. Do you think I could store the objects in another vector<Sprite> and then push pointers to those objects into a vector<Sprite*>? Or do you think the pointers might become invalid?

I load in the sprites from separate XML file, so the number of objects is always changing else I would use an array.
The easiest way IMO would be to make a container of smart pointers and use that. Or just use a boost::ptr_vector.
Do you think I could store the objects in another vector<Sprite> and then push pointers to those objects into a vector<Sprite*>? Or do you think the pointers might become invalid?


You will still get objects sliced with this solution unless you will make a vector for all derived classes of Sprite. I agree with firedraco, it will much easier to just create a container of smart pointers.
Thanks for the responses, guys, and I learned something new: the std::tr1::shared_ptr<>. I was worried I wasn't going to find it in XCode, but it's there.

I ultimately set up a std::map<string, shared_ptr<> > to make the correct function calls. Thanks!

-Chris
If you want, also go check out the boost pointer containers. They might be easier to use depending on what you want the pointers for.
Topic archived. No new replies allowed.