简体   繁体   中英

Polymorphism doesn't work as it should

I have spent hours one finding this bug, now at least I know where is the problem but I have no idea why.

So I have:

std::vector< std::vector <Organism* > >world;

I have base class Organism and child classes Beetle and Ant .

In base class Organism I have virtual functions:

    private:
         bool energy;
    public:
    Organism():energy(true){}
    virtual void removeEnergy(){
        energy = false;
    }
    virtual bool hasEnergy(){
        return energy;
    }

    virtual void resetEnergy(){
        energy = true;
    }

And I have NOT overwritten them in any of the child classes. I have called base class constructor in child classes.

When I call this function:

void World::replaceOrganism(int x, int y, int newX, int newY){  
        world[newX][newY] = world[x][y];
        world[x][y] = new Organism;
        world[newX][newY]->removeEnergy(); // this line
}

It removes energy only from this class objects. That means if in vector world are multiple Beetles then by this line:

world[newX][newY]->removeEnergy();

energy is removed from all of them.

I think its something with vectors. Anyone have any suggestions? If you need more info -> comment I will add.

One more thing if I remove that line:

world[newX][newY]->removeEnergy();

then energy of Organism class objects or its children doesn't change.

EDITED

Creating world vector:

world.resize(worldSizeX);

    for (int x = 0; x < worldSizeX; x++){
        world[x] = std::vector< Organism* >(worldSizeY);

        // INITATES world ARRAY
        for (int y = 0; y < worldSizeY; y++){
            world[x][y] = new Organism;
        }
        // !INITATES world ARRAY
    }

EDITED

Changing replaceOrganism function with this:

void World::replaceOrganism(int x, int y, int newX, int newY){  
        delete world[newX][newY];   
        world[newX][newY] = world[x][y];
        delete world[x][y];
        world[x][y] = new Organism;
 }

deletes all class objects that word[newX][newY] is pointing, but function is called only once.

EDITED

function that replaces Organism class objects with its children.

bool World::createOrganism(int x, int y, Organism* organism){
    Organism* empty = new Organism;
    if (world[x][y]->type() != empty->type()){
        delete empty;
        return false;
    }
    else{
        delete empty;
        world[x][y] = organism;
        return true;
    }
}

I call it by:

createOrganism(2,3,new Beetle);

EDITED

void World::generateOrganisms(Organism* organism, int amount){
    while (amount != 0){
        int x = rand() % worldSizeX;
        int y = rand() % worldSizeY;
        if (createOrganism(x, y, organism)){
            amount--;
        }
    }
}

Everything is pointing to the same object.

In generateOrganisms(Organism* organism, int amount) all the several pointers you set up refer to the same single organism. So all the same Beetle.

You need to foresee an additional virtual function for your Organism :

Organism *clone()  {
   // create a new organism of the same type 
   }   

This virtual function should be overwritten for each child, to create a new organism using the correct constructor.

You could then update your creation function:

bool World::createOrganism(int x, int y, Organism* organism){
    Organism* empty = new Organism;
    if (world[x][y]->type() != empty->type()){
        delete empty;
        return false;
    }
    else{
        delete empty;
        world[x][y] = organism->clone();  // use a clone, not the original
        return true;
    }
}

In addition, I'm not sure that all unused objects are deleted as needed (at least, difficult to say with only the snipets you provide). It could be worth investigating the potential use of shared_ptr, to avoid leaking memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM