Vectors of classes

This is a discussion on Vectors of classes within the C++ Programming forums, part of the General Programming Boards category; I have a class Monster for NPCs and so on in the game, and I want to create a vector ...

Vectors of classes

I have a class Monster for NPCs and so on in the game, and I want to create a vector containing all the currently active monsters. As they die or get spawned I figure I'll pushback or popback them in or out of the vector.

Drawimage is just a function that uses SDL to blit the monster graphic to the screen. I'm passing it the x,y coordinates and height/width of each Monster.

Basically when I referenced Monster1 and Monster2 directly everything was fine, but when I put the vector in and referenced them from the vector I don't get any error but the monsters don't display on screen.

I tried a few different combinations, I tried using pushback originally instead of an array reference but that didn't work either, the interesting thing though is that if I put the two MonsterList[0]=Monster1 lines into the render step it works. Is this some kind of scope issue?

The reason I'm passing the individual components of Monster rather than the whole object is that I also pass things to drawimage() that aren't Monsters or even related classes.

>> Is this some kind of scope issue?
Maybe, but we wouldn't be able to tell with the posted code. If you have more than one variable named MonsterList or Monster1 or Monster2 in your program, then you might have a problem there. For example, if a Monster1 exists inside main, maybe that is getting added instead of the global one. Or if there is another MonsterList inside main, it gets items assigned instead of the global one.

Gah... I think I figured it out. I went to copy more code across but then looking at it it occurred to me the monsters were assigned to the vector before I specified their positions. I pasted it just after and they appear fine. Although they don't move - this must be because their assignment occurs before the main loop even begins so their position never changes.

It's quite long now so I've tried to still prune it right down to the important parts.

So I guess I didn't really understand how vectors work. I just assumed that once I stored a monster in the vector then anything I do to the monster will be reflected in that entry in the vector... but it's more like it creates a copy of the monster at that point in time and puts it in that slot of the vector - is that right?

Do I need to put the monsters into the vector after I've finished running all alterations on the monsters for that frame? That seems kind of tricky. I'd have to pull the monster out and replace it with the updated monster. Is there a better way to do it?

So I guess I didn't really understand how vectors work. I just assumed that once I stored a monster in the vector then anything I do to the monster will be reflected in that entry in the vector... but it's more like it creates a copy of the monster at that point in time and puts it in that slot of the vector - is that right?

Yes, the vector stores a copy of what you insert into it.

Originally Posted by Dondrei

Do I need to put the monsters into the vector after I've finished running all alterations on the monsters for that frame? That seems kind of tricky. I'd have to pull the monster out and replace it with the updated monster. Is there a better way to do it?

You could populate the vector, and then call the functions of those monster objects stored in the vector.

That said, take another look at what matsp wrote in post #2, especially this part:

Originally Posted by matsp

If you are planning to have different kinds of monsters, you probably want a vector of pointers to the base-monster class and use virtual methods to achieve the interactions.

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.

Right, so one solution would be what I suggested earlier: That you store a pointer (Elysia will probably suggest that you use a safe-pointer, e.g. shared_ptr<>) to the monster, so that what is stored in the vector is the ADDRESS of the original monster, rather than storing a copy of the monster in the vector.

It's either that, or modify the vector-content rather than the original monster.

Sorry... I'm a dork, I wasn't thinking clearly. The problem is that in my movement code I was still referring to Monster1 and Monster2, I should've changed that to MonsterList.at(0) and MonsterList.at(1)... anyway I just did that and presto.

I'm planning to have different kinds of monsters, but Monster will be the base class, I think all the basic features of the monster will be defined at this level (certainly things like position and velocity and so on), if I have classes underneath Monster they'll probably just divide up monsters that shoot from monsters that don't or something. So I think this way makes sense... what do you think?

I'm planning to have different kinds of monsters, but Monster will be the base class, I think all the basic features of the monster will be defined at this level (certainly things like position and velocity and so on), if I have classes underneath Monster they'll probably just divide up monsters that shoot from monsters that don't or something. So I think this way makes sense... what do you think?

Or is the pointer method more efficient?

If you have classes that inherit from a base-class, you should definitely use pointers, as you will otherwise suffer from "slicing". You will also need to make all functions of the monster into virtual classes.

I think you mean virtual functions.
Perhaps even make the pure virtual.

Yes - fingers typing without brain involved ... [Another reason I don't give help in PM's is that when I type something wrong, the helpee is not getting it corrected by someone who knows roughly what I mean].

And my compiler gave me a warning about comparison of signed and unsigned integer expressions. Which I thought was weird because I assumed the size method would return an int. Maybe I'm not really understanding what I'm doing. I tried:

I took a look into virtual functions, sounds interesting, I'm already kind of doing something similar because I have an Avatar class that's also derived from Creature. Both Avatar and Monster have a movement method but they aren't defined through Creature, I just created a moveavatar() in Avatar and a movemonster() in Monster. What's the difference between doing that and creating a virtual move() in Creature and then defining it differently in Monster and Avatar? I mean, the names were just what I happened to pick, if I renamed both moveavatar() and movemonster() to move() what would the difference be then?

Just make i an unsigned int (or more correctly vector<monster>::size_type).

As an aside, I'd like to see the long line of drawimage to be modified. I'm not sure if a monster should know how to draw itself (that may be a good option), or if you simply should make a function that takes a parameter of a monster to be drawn. But certainly repeating a lot of MonsterList.at(i).*** is not right here, I'd say.

Virtual functions have the benefit over regular functions that the TYPE of the object at the point of calling doesn't have to be know exactly - say for example we have:

See, this part of the code started out life as the basic SDL blitting code you see in SDL's tutorials and in a lot of game development forums, I haven't altered much of it since I brought it in. So basically the code was originally non-object oriented (procedural?) and I've been progressively working classes into it because I've never done object oriented programming before and figured it would be a good way to learn.

So at the moment I'm just passing bits of the classes to the functions - partly it's because I pass other things to the blitter apart from Creatures, like the background for instance. I guess the paradigm-correct thing to do would be to create a class above Creature, like Sprite or something, from which Creature can inherit height, width and position. Then the background and other sprites can be of the Sprite class, and I can pass them by reference to drawimage.

Originally Posted by matsp

Now, CreatureList is a list of creatures. Without virtual, it would call creature::move(), rather than monster::move or friendly::move.

Oh right, so the method in the parent class takes precedence? I wondered what would happen in that case.

You're right, I should probably unify the move methods with virtual functions.

Even if I change "int i" to "signed int i" I still get comparison of signed and unsigned integer expressions.

Obviously, since std::vector<Monster>::size_type is an unsigned integer type, but you changed i to be a signed int. Rather, just use std::vector<Monster>::size_type, as you did in your second example.

Originally Posted by Dondrei

Oh right, so the method in the parent class takes precedence? I wondered what would happen in that case.

Not quite. Suppose you have a pointer to creature that actually points to a monster object, with creature being a public base class of monster. If you invoke a virtual member function via this pointer, then the actual function that is called is the one from the monster class. If you invoke a non-virtual member function, then the actual function that is called is the one from the creature class, because the pointer is a pointer to creature. If the pointer was a pointer to monster, the member function from the monster class would be called, whether or not the member function is virtual.

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.