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