Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Need help: a vector of different extended classes


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
9 replies to this topic

#1 iwoplaza   Members   -  Reputation: 174

Like
0Likes
Like

Posted 15 March 2014 - 09:58 AM

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 :).



Sponsor:

#2 Brother Bob   Moderators   -  Reputation: 9289

Like
3Likes
Like

Posted 15 March 2014 - 10:08 AM

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.



#3 iwoplaza   Members   -  Reputation: 174

Like
0Likes
Like

Posted 15 March 2014 - 10:28 AM

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);


#4 TheComet   Crossbones+   -  Reputation: 1905

Like
0Likes
Like

Posted 15 March 2014 - 10:45 AM

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

Edited by TheComet, 15 March 2014 - 11:44 AM.

YOUR_OPINION >/dev/null

#5 Adam_42   Crossbones+   -  Reputation: 2795

Like
4Likes
Like

Posted 15 March 2014 - 10:54 AM

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.


Edited by Adam_42, 15 March 2014 - 01:39 PM.


#6 SiCrane   Moderators   -  Reputation: 10367

Like
3Likes
Like

Posted 15 March 2014 - 11:28 AM

// 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.

#7 iwoplaza   Members   -  Reputation: 174

Like
0Likes
Like

Posted 15 March 2014 - 02:16 PM

Thanks for everything guys :)



#8 wintertime   Crossbones+   -  Reputation: 2633

Like
0Likes
Like

Posted 15 March 2014 - 03:45 PM

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.



#9 ChaosEngine   Crossbones+   -  Reputation: 3008

Like
0Likes
Like

Posted 16 March 2014 - 02:44 PM

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

#10 wintertime   Crossbones+   -  Reputation: 2633

Like
0Likes
Like

Posted 17 March 2014 - 08:01 AM

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.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS