Need help: a vector of different extended classes

Started by
8 comments, last by wintertime 10 years, 1 month ago

Hello there.

I want to make a list of entities that are gonna be updated every tick. So, I created a class named Entity, and gave it a couple of functions:


class Entity{
    public:
        int uniqueID;

        Vec3f loc;
        Vec2f res;
        Vec2f vel;
        float rot;

        virtual void onUpdate();
        virtual void onSpawned();
        virtual string getNameID();
        vector<GameData> gameData;
};

Then, I created a vector of these entities:


vector<Entity> entities;

After that, I wanted an arrow entity, so I created a new class EntityArrow that is an extension of Entity:


class EntityArrow : public Entity{
    public:
        EntityArrow();
        EntityArrow(Vec3f argLoc,Vec2f argRes);
        string getNameID();
        void onUpdate();
        void onSpawned();
};

And now comes the problem, when I try to add a new EnttiyArrow to the entities list: entities.push_back(EntityArrow()); it is still treated as an Entity. For instance, if I overrided the onUpdate() function in EntityArrow to print out something in the console, it would do something that is in the Entity's onUpdate() , and not the EntityArrow's. I have already tried to make a vector out of references to Entity class : vector<Entity*> entities , but I still have a lot of problems with it.

Is there a better way to do it? Thanks in advance :).

Advertisement

Look up slicing; your vector stores Entity objects by value, so only the Entity part of your EntityArrow ends up in the vector. Your vectors has to store pointers and you need to allocate your Entity objects dynamically instead.

So I should use this method right? vector<Entity*> entities

Well, if yes, than I still have problems with it. Sure, it works for the aspect of overriding the functions properly, but sometimes when I try to render it or just add another entity, it doesn't show up, or just doesn't add to the vector.

Is this method of adding the Entity into the vector correct?


EntityArrow arrow = EntityArrow();
entities.push_back(&arrow);
No, because that way, arrow will be destroyed as soon as it goes out of scope, and your list of entities will be holding an invalid pointer pointing somewhere above the stack. You have to use new and delete.
[EDIT] As SiCrane points out below, delete the element before removing it from the list.
// adding entities
Entity* arrow = new EntityArrow();
entities.push_back(arrow);

// removing entities
delete *it; // make sure to delete the entity being removed from the list
entities.erase(it);
Better yet, use smart pointers, so you don't have to manually delete the entities you remove from the list:

std::vector< std::shared_ptr<Entity> > entities;

// adding entities
std::shared_ptr<Entity> arrow = new EntityArrow();
entities.push_back(arrow);

// removing entities
entities.erase(it);
// entity is automatically deleted when you remove it
"I would try to find halo source code by bungie best fps engine ever created, u see why call of duty loses speed due to its detail." -- GettingNifty

That's not correct. When Brother Bob said you have to allocate the entity objects dynamically he meant that you need to allocate them with the new operator. This means you have to delete them when you remove them too.


EntityArrow *arrow = new EntityArrow();
entities.push_back(arrow);

To avoid the need for manual deletion you can use smart pointers:


// Requires C++11 compiler

std::vector<std::unique_ptr<Entity>> entities;

entities.push_back(std::unique_ptr<Entity>(new EntityArrow()));

Edit: Apologies for the similar post. The previous one wasn't there when I started writing it. It's not quite a duplicate though - the choice of smart pointer is different.


// removing entities
entities.erase(it);
delete *it; // make sure to delete the entity being removed from the list

You're trying to delete an element you've just erased. You may want to reconsider your order of operations here.

Thanks for everything guys :)

Contrary to what the other people said, the simplest solution is to not throw all entities into one vector only to later having to check their type through virtual calls.

The point of templates is that they know the exact type:


vector<EntityArrow> arrows;

Btw., if you create a large hierarchy of classes derived from Entity you'll probably discover later that it leads to problems. You'll be tempted to duplicate some aspects or move unrelated things up in the hierarchy where they not belong, because not all objects can be categorized into a regular tree. Better to avoid that from beginning and use composition instead of inheritance.

Contrary to what the other people said, the simplest solution is to not throw all entities into one vector only to later having to check their type through virtual calls.
The point of templates is that they know the exact type:


vector<EntityArrow> arrows;
Btw., if you create a large hierarchy of classes derived from Entity you'll probably discover later that it leads to problems. You'll be tempted to duplicate some aspects or move unrelated things up in the hierarchy where they not belong, because not all objects can be categorized into a regular tree. Better to avoid that from beginning and use composition instead of inheritance.


The exact type of


vector<Entity*>

is perfectly well known; it's a vector of pointer to Entity.
The behaviour is well-defined within the language and works exactly as expected.

I didn't vote your reply down because I agree with what you're saying about class design, composition, etc., but your reply is lacking sufficient context to make it useful to the OP.

Simply saying don't "throw all entities into one vector" doesn't really help the OP with his/her problem. They are clearly looking to use a polymorphic pattern, and that's a completely legitimate way of achieving their goal. That's not to say there aren't better ways, but for the moment, it's better for the OP to understand their current problem.

if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight

That the type of vector<Entity*> is well known is true, but irrelevant and I did not write that it was not.

What I tried to hint at was that the problem stems from using vector<Entity> and filling it with objects that are only derived from Entity. Then I gave the example of fixing it by using vector<EntityArrow>, which is a different and possibly better/easier solution than switching to a pointer type.

Btw., he explicitly asked if there was a better way to do it, therefore its not wrong to tell him there are other solutions than going the way of polymorphism. I could have elaborated it more, but I first wanted to see how much he would be interested in that.

This topic is closed to new replies.

Advertisement