Problems Allocating Objects of Derived Class Where Base Class has Abstract Virtual Functions

Posted by user1743901 on Stack Overflow See other posts from Stack Overflow or by user1743901
Published on 2012-11-24T23:02:23Z Indexed on 2012/11/24 23:03 UTC
Read the original article Hit count: 321

Filed under:
|
|

I am trying to get this Zombie/Human agent based simulation running, but I am having problems with these derived classes (Human and Zombie) who have parent class "Creature". I have 3 virtual functions declared in "Creature" and all three of these are re-declared AND DEFINED in both "Human" and "Zombie". But for some reason when I have my program call "new" to allocate memory for objects of type Human or Zombie, it complains about the virtual functions being abstract. Here's the code:

definitions.h

#ifndef definitions_h
#define definitions_h
class Creature;
class Item;
class Coords;

class Grid
{

public:
      Creature*** cboard;
      Item*** iboard;

      int WIDTH;
      int HEIGHT;

      Grid(int WIDTHVALUE, int HEIGHTVALUE);
      void FillGrid(); //initializes grid object with humans and zombies  
      void Refresh(); //calls Creature::Die(),Move(),Attack(),Breed() on every square
      void UpdateBuffer(char** buffer);
      bool isEmpty(int startx, int starty, int dir);
      char CreatureType(int xcoord, int ycoord);
      char CreatureType(int startx, int starty, int dir);

};

class Random
{
    public:
        int* rptr;
        void Print();
        Random(int MIN, int MAX, int LEN);
        ~Random();
    private:
        bool alreadyused(int checkthis, int len, int* rptr);
        bool isClean();
        int len;
};

class Coords
{
  public:   
      int x;
      int y;
      int MaxX;
      int MaxY;

      Coords() {x=0; y=0; MaxX=0; MaxY=0;}
      Coords(int X, int Y, int WIDTH, int HEIGHT) {x=X; y=Y; MaxX=WIDTH; MaxY=HEIGHT; }

      void MoveRight();
      void MoveLeft();
      void MoveUp();
      void MoveDown();
      void MoveUpRight();
      void MoveUpLeft();
      void MoveDownRight();
      void MoveDownLeft();
      void MoveDir(int dir);
      void setx(int X) {x=X;}
      void sety(int Y) {y=Y;}
};

class Creature
{

public:
      bool alive;
      Coords Location;
      char displayletter;

      Creature() {Location.x=0; Location.y=0;}
      Creature(int i, int j) {Location.setx(i); Location.sety(j);} 

      virtual void Attack() =0;
      virtual void AttackCreature(Grid G, int attackdirection) =0;
      virtual void Breed() =0;

      void Die();
      void Move(Grid G);
      int DecideSquare(Grid G);
      void MoveTo(Grid G, int dir); 

};

class Human : public Creature 
{
public:      
      bool armed; //if armed, chances of winning fight increased for next fight 
      bool vaccinated; //if vaccinated, no chance of getting infected

      int bitecount; //if a human is bitten, bite count is set to a random number
      int breedcount; //if a human goes x steps without combat, will breed if next to a human
      int starvecount; //if a human does not eat in x steps, will die 

      Human() {displayletter='H';} 
      Human(int i, int j) {displayletter='H';}

      void Attack(Grid G);
      void AttackCreature(Grid G, int attackdirection);
      void Breed(Grid G); //will breed after x steps and next to human

      int DecideAttack(Grid G);





};

class Zombie : public Creature
{
   public:
      Zombie() {displayletter='Z';}
      Zombie(int i, int j) {displayletter='Z';}

      void Attack(Grid G); 
      void AttackCreature(Grid G, int attackdirection);
      void Breed() {} //does nothing

      int DecideAttack(Grid G);
      void AttackCreature(Grid G, int attackdirection);

};

class Item
{

};



#endif

definitions.cpp

#include <cstdlib>
#include "definitions.h"

Random::Random(int MIN, int MAX, int LEN) //constructor
{
    len=LEN;
    rptr=new int[LEN]; //allocate array of given length
    for (int i=0; i<LEN; i++)
    {
       int random;

       do {
           random = rand() % (MAX-MIN+1) + MIN;
       } while (alreadyused(random,LEN,rptr));

       rptr[i]=random;
    }

}

bool Random::alreadyused(int checkthis, int len, int* rptr)
{
    for (int i=0; i<len; i++)
    {
        if (rptr[i]==checkthis)
            return 1;
    }
    return 0;
}

Random::~Random()
{
       delete rptr;
}



Grid::Grid(int WIDTHVALUE, int HEIGHTVALUE)
{
     WIDTH = WIDTHVALUE;
     HEIGHT = HEIGHTVALUE;
     //builds 2d array of creature pointers
     cboard = new Creature**[WIDTH];
     for(int i=0; i<WIDTH; i++)
     {
             cboard[i] = new Creature*[HEIGHT];
     }

     //builds 2d array of item pointers
     iboard = new Item**[WIDTH];
     for (int i=0; i<WIDTH; i++)
     {
              iboard[i] = new Item*[HEIGHT];
     }
}

void Grid::FillGrid()
{
     /* For each creature pointer in grid, randomly selects whether to initalize
     as zombie, human, or empty square. This methodology can be changed to initialize
     different creature types with different probabilities */

     int random;

     for (int i=0; i<WIDTH; i++)
     {
         for (int j=0; j<HEIGHT; j++)
         {
             Random X(1,100,1); //create a single random integer from [1,100] at X.rptr
             random=*(X.rptr);
             if (random < 20)
                cboard[i][j] = new Human(i,j);
             else if (random < 40) 
                  cboard[i][j] = new Zombie(i,j); 
             else 
                  cboard[i][j] = NULL;
         }
     } //at this point every creature pointer should be pointing to either
     //a zombie, human, or NULL with varying probabilities 

}

void Grid::UpdateBuffer(char** buffer)
{
     for (int i=0; i<WIDTH; i++)
     {
         for (int j=0; j<HEIGHT; j++)
         {
             if (cboard[i][j])
                buffer[i][j]=cboard[i][j]->displayletter;
             else
                 buffer[i][j]=' ';
         }
     }

}

bool Grid::isEmpty(int startx, int starty, int dir)
{
     Coords StartLocation(startx,starty,WIDTH,HEIGHT);
     switch(dir)
     {
                case 1:
                     StartLocation.MoveUp();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 2:
                     StartLocation.MoveUpRight();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 3:
                     StartLocation.MoveRight();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 4:
                     StartLocation.MoveDownRight();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 5:
                     StartLocation.MoveDown();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 6:
                     StartLocation.MoveDownLeft();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 7:
                     StartLocation.MoveLeft();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 8:
                     StartLocation.MoveUpLeft();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0; 
     }
     return 1;
}

char Grid::CreatureType(int xcoord, int ycoord)
{
     if (cboard[xcoord][ycoord]) //if there is a creature at location xcoord,ycoord
        return (cboard[xcoord][ycoord]->displayletter);
     else //if pointer at location xcoord,ycoord is null, return null char
         return '\0';
}

char Grid::CreatureType(int startx, int starty, int dir)
{
     Coords StartLocation(startx,starty,WIDTH,HEIGHT);
     switch(dir)
     {
                case 1:
                     StartLocation.MoveUp();
                     if (cboard[StartLocation.x][StartLocation.y])
                        return (cboard[StartLocation.x][StartLocation.y]->displayletter);

                case 2:
                     StartLocation.MoveUpRight();
                     if (cboard[StartLocation.x][StartLocation.y])
                        return (cboard[StartLocation.x][StartLocation.y]->displayletter);
                case 3:
                     StartLocation.MoveRight();
                     if (cboard[StartLocation.x][StartLocation.y])
                        return (cboard[StartLocation.x][StartLocation.y]->displayletter);
                case 4:
                     StartLocation.MoveDownRight();
                     if (cboard[StartLocation.x][StartLocation.y])
                        return (cboard[StartLocation.x][StartLocation.y]->displayletter);
                case 5: 
                     StartLocation.MoveDown();
                     if (cboard[StartLocation.x][StartLocation.y])
                        return (cboard[StartLocation.x][StartLocation.y]->displayletter);
                case 6:
                     StartLocation.MoveDownLeft();
                     if (cboard[StartLocation.x][StartLocation.y])
                        return (cboard[StartLocation.x][StartLocation.y]->displayletter);
                case 7:
                     StartLocation.MoveLeft();
                     if (cboard[StartLocation.x][StartLocation.y])
                        return (cboard[StartLocation.x][StartLocation.y]->displayletter);
                case 8: 
                     StartLocation.MoveUpLeft();
                     if (cboard[StartLocation.x][StartLocation.y])
                        return (cboard[StartLocation.x][StartLocation.y]->displayletter);

     } //if function hasn't returned by now, square being looked at is pointer to null
     return '\0'; //return null char 

}


void Coords::MoveRight() {(x==MaxX)? (x=0):(x++);}
void Coords::MoveLeft() {(x==0)? (x=MaxX):(x--);}
void Coords::MoveUp() {(y==0)? (y=MaxY):(y--);}
void Coords::MoveDown() {(y==MaxY)? (y=0):(y++);} 
void Coords::MoveUpRight() {MoveUp(); MoveRight();}
void Coords::MoveUpLeft() {MoveUp(); MoveLeft();}
void Coords::MoveDownRight() {MoveDown(); MoveRight();}
void Coords::MoveDownLeft() {MoveDown(); MoveLeft();}
void Coords::MoveDir(int dir)
{
     switch(dir)
     {
                case 1:
                     MoveUp();
                     break;
                case 2:
                     MoveUpRight();
                     break;
                case 3:
                     MoveRight();
                     break;
                case 4:
                     MoveDownRight();
                     break;
                case 5:
                     MoveDown();
                     break;
                case 6:
                     MoveDownLeft();
                     break;
                case 7:
                     MoveLeft();
                     break;
                case 8:
                     MoveUpLeft();
                     break;
                case 0:
                     break;
     }
}


void Creature::Move(Grid G)
{
     int movedir=DecideSquare(G);
     MoveTo(G,movedir);
}

int Creature::DecideSquare(Grid G)
{
     Random X(1,8,8); //X.rptr now points to 8 unique random integers from [1,8]
     for (int i=0; i<8; i++)
     {
         int dir=X.rptr[i];
         if (G.isEmpty(Location.x,Location.y,dir))
            return dir;
     }
     return 0;
}

void Creature::MoveTo(Grid G, int dir)
{
     Coords OldLocation=Location;
     Location.MoveDir(dir); 
     G.cboard[Location.x][Location.y]=this; //point new location to this creature
     G.cboard[OldLocation.x][OldLocation.y]=NULL; //point old location to NULL
}

void Creature::Die()
{
     if (!alive)
        {
                delete this;
                this=NULL;
        }
}

void Human::Breed(Grid G)
{
     if (!breedcount)
     {
        Coords BreedLocation=Location;
        Random X(1,8,8);
        for (int i=0; i<8; i++)
        {
            BreedLocation.MoveDir(X.rptr[i]);
            if (!G.cboard[BreedLocation.x][BreedLocation.y])
            {
                 G.cboard[BreedLocation.x][BreedLocation.y])=new Human(BreedLocation.x,BreedLocation.y);
                 return;
            }  
        } 
     }
}                                        



int Human::DecideAttack(Grid G)
{
     Coords AttackLocation=Location;
     Random X(1,8,8);
     int attackdir;
     for (int i=0; i<8; i++)
     {
         attackdir=X.rptr[i];
         switch(G.CreatureType(Location.x,Location.y,attackdir))
         {
               case 'H':
                    break;
               case 'Z':
                    return attackdir;
               case '\0':
                    break;
               default:
                    break;
         } 
      } 
      return 0; //no zombies!                                              
}

int AttackRoll(int para1, int para2)
{
    //outcome 1: Zombie wins, human dies
    //outcome 2: Human wins, zombie dies
    //outcome 3: Human wins, zombie dies, but human is bitten

    Random X(1,100,1);
    int roll= *(X.rptr);
    if (roll < para1)
       return 1;

    else if (roll < para2) 
       return 2;

    else
       return 3;
}

void Human::AttackCreature(Grid G, int attackdirection)
{
    Coords AttackLocation=Location;
    AttackLocation.MoveDir(attackdirection);

    int para1=33;
    int para2=33;

    if (vaccinated)
         para2=101; //makes attackroll > para 2 impossible, never gets infected

    if (armed)
         para1-=16; //reduces chance of zombie winning fight 


    int roll=AttackRoll(para1,para2);
         //outcome 1: Zombie wins, human dies
         //outcome 2: Human wins, zombie dies
         //outcome 3: Human wins, zombie dies, but human is bitten
    switch(roll)
    {
        case 1: 
             alive=0; //human (this) dies
             return;
        case 2:
             G.cboard[AttackLocation.x][AttackLocation.y]->alive=0;
             return; //zombie dies
        case 3:
             G.cboard[AttackLocation.x][AttackLocation.y]->alive=0; //zombie dies
             Random X(3,7,1); //human is bitten
             bitecount=*(X.rptr);
             return;
     }
}

int Zombie::DecideAttack(Grid G)
{
     Coords AttackLocation=Location;
     Random X(1,8,8);
     int attackdir;
     for (int i=0; i<8; i++)
     {
         attackdir=X.rptr[i];
         switch(G.CreatureType(Location.x,Location.y,attackdir))
         {
               case 'H':
                    return attackdir;
               case 'Z':
                    break;
               case '\0':
                    break;
               default:
                    break;
         } 
      } 
      return 0; //no zombies!                                              
}

void Zombie::AttackCreature(Grid G, int attackdirection)
{
    int reversedirection;
    if (attackdirection < 9 && attackdirection>0)
    {
        (attackdirection<5)? (reversedirection=attackdirection+4):(reversedirection=attackdirection-4);

    }
    else
        reversedirection=0; //this should never happen

    //when a zombie attacks a human, the Human::AttackZombie() function is called
    //in the "reverse" direction, utilizing that function that has already been written
    Coords ZombieLocation=Location;
    Coords HumanLocation=Location;
    HumanLocation.MoveDir(attackdirection);

    if (G.cboard[HumanLocation.x][HumanLocation.y]) //if there is a human there, which there should be
       G.cboard[HumanLocation.x][HumanLocation.y]->AttackCreature(G,reversedirection);

}


void Zombie::Attack(Grid G)
{
     int attackdirection=DecideAttack(G);
     AttackCreature(G,attackdirection);
}

main.cpp

#include <cstdlib>
#include <iostream>
#include "definitions.h"

using namespace std;

int main(int argc, char *argv[])
{
    Grid G(500,500);

    system("PAUSE");
    return EXIT_SUCCESS;
}

© Stack Overflow or respective owner

Related posts about c++

Related posts about inheritance