Problem with Virtual Function

Started by
11 comments, last by signal_ 15 years, 5 months ago
I recently have begun to use virtual functions. I am having a problem at run time. Can someone please check my syntax and methods? See below for an explanation of the outcome. Here is my code. I have broken it up into files because that is how it is in my work directory. I think the problem may lie with my syntax. entity.h file:

class Entity
{
    protected:
        int xCo; int yCo;   // coordinates for the entity

    public:

        Entity( eID );

        ~Entity();
        
        virtual void update();                                   
};





Entity.cpp file:

#include "entity.h"



Entity::Entity( eID )
{
    // do stuff
}


Entity::~Entity()
{
}



void Entity::update()  // Update Function -- called once per frame.
{
    std::cout << "***Update" << std::endl;
}






Then I have a derived class that I want to use. derive.h file:

#include "entity.h"


class Derive: public Entity
{
  public:
    Derive( eID );
    ~Derive();

    void update();

};





derive.cpp file:

#include "derive.h"



Derive::Derive( eID ):Entity( eID )
{
    //

}

void Derive::update()
{
    std::cout << "UpdateDerive!!!!!!!!!!!!!!!" << std::endl;
}


Derive::~Derive()
{
}






Basically, I create a vector: std::vector<Entity*> entities; Then I call a function: void EntityList::updateEntity() { for( int i = 0; i < entities.size(); i++ ) // i < entity_ID { entities->update(); } } When I run the program it says MS Windows detected a problem & closes. Compiles and links without problem. I also completely rebuilt the project. When I remove the virtual keyword, i.e. type "void update();" instead of "virtual void update();" in the entity.h file the program runs and exits fine. Of course the added functionality of derived classes isn't there but it runs. What am I doing incorrectly? Please assist.
Advertisement
You must make the destructor of the base class 'virtual'. (I assume you do actually have code somewhere that allocates entities with 'new' and puts them into the vector, and which calls 'delete' on those pointers later.) (You must also ensure that each created object is only deallocated once.)

Basically: the destructor is a member function, too. If it's not 'virtual', then it won't do any dynamic dispatch, which means the base destructor gets called on the pointed-at object, even if it's actually an instance of the derived class. And that's bad.
How are you adding entities to your vector? It sounds like you've got some bum pointers in there.
As a rule, a class with a virtual function should have a virtual destructor. Here is a link that more correctly explains the rule (section 20.7). Other than that, I don't know what the problem could be. I assume that entities is filled with valid objects, of course.

[edit]

Ah fetch! Ninja'd twice!
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
1) Run the program in your debugger to, among other things, find out exactly where the crash occurs (clicky)
2) Entity must have a virtual destructor. As is, the following code may explode:
Entity* foo = new Derive();delete foo;

3) Please always copy & paste real source code. (If you really are directly copy and pasting a class named "Derive" from what you're compiling, you may want to start naming your classes better ;-))

If the crash is actually occurring on the update() call, I'm guessing your vector contains uninitialized, deleted, or otherwise invalid pointers. Since update() doesn't access any of the member variables of the class (or functions that do so themselves), the implicit "this" pointer isn't actually being used when update isn't virtual. By making the function virtual, your compiler beings using the implicit "this" pointer to get the virtual table so it can call the correct function for the class you're using.

A way to confirm this would be to make Entity::update print out xCo and yCo instead of just "***Update". This would cause the code to crash even if the function isn't virtual if my guess is right.

Edit: Ninja'd thrice <_<
Wow! Thanks for all the quick replies. I was asked about how I am adding entities to my vector, so I will include that now:

void EntityList::addEntity(int x, int y){    Entity* temp_entity = new Entity( entity_ID );    // now increment ID entity!    entity_ID++;    temp_entity->SetX( x );    temp_entity->SetY( y );    entities.push_back( temp_entity );   // create the entity!    delete temp_entity;}



I am afraid that I need to read through all the responses thus far to offer a better reply. But until then thanks for all the responses!
Why on earth are you deleting it after you add it?
SiCrane,

I am obviously confused here... By deleting it I am just ruining what I just did, right?

What I want is a container for the entities and all these different entities to use their respective update functions.

So, do I need to store all my entities in a vector and store my entity pointers in another? Sorry I am confused.
Quote:Original post by signal_
SiCrane,

I am obviously confused here... By deleting it I am just ruining what I just did, right?

What I want is a container for the entities and all these different entities to use their respective update functions.

So, do I need to store all my entities in a vector and store my entity pointers in another? Sorry I am confused.


No, the problem is you create the object, store it, and then delete it. That means that the vector now contains a bunch of deleted objects. Trying to use them crashes your program. You should do something more like

void EntityList::addEntity(int x, int y){    Entity* temp_entity = new Entity( entity_ID );    // now increment ID entity!    entity_ID++;    temp_entity->SetX( x );    temp_entity->SetY( y );    entities.push_back( temp_entity );   // create the entity!}


And in the destructor of the class (or somewhere that it will be called so your memory doesn't leak), iterate through the vector and delete the objects, like this:

for (int i = 0; i < entities.size(); i++){    delete entities;}entities.clear();
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Mike, by removing that delete line and making the changes you outlined everything works now the way I intended.

I am weak with pointers and usually avoid using them, which explains my confusion with new and delete. Also there are some aspects of OOP that I am very shaky with. I come from a C background and was not a comp sci student at uni (this is obvious to all of you, but I am being complete...lol).

I have a lot to learn and I truly appreciate everyone who took the time to respond to my post. Thank you so much!

Unfortunately, I must run out for a quick errand so I will write more when I return.

This topic is closed to new replies.

Advertisement