Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Tuesday, August 16, 2016

C++ ecosystem simulator (inheritance)

C++ ecosystem simulator (inheritance)


I am a beginner developing an ecosystem in C++. It works like this:

I have PLANTS(not shown here) and ANIMALS on my grid.

If something is an ANIMAL, it is either a CARNIVORE or an HERBIVORE.

I created this hierarchy:

class ANIMAL  {  private:      int a_CUR_food_lvl;       const int a_MAX_food_lvl;       const int a_hunger_rate;     public:        ANIMAL(int curr, int max, int rate)          : a_CUR_food_lvl(curr),          a_MAX_food_lvl(max),          a_hunger_rate(rate)      {}         virtual ~ANIMAL()       {          delete this;       }        virtual void Move() = 0;      virtual void Eat() = 0;      virtual void Evade() = 0;      virtual void Reproduce() = 0;      virtual void Die() = 0;      virtual void Age() = 0;        virtual int get_a_CUR_food_lvl() { return a_CUR_food_lvl; };      virtual int get_a_MAX_food_lvl() { return a_MAX_food_lvl; };      virtual int get_a_hunger_rate() { return a_hunger_rate; };  }; //end ANIMAL class      //#################################################################  class CARNIVORE : public ANIMAL  {  public:        class WOLF : public ANIMAL      {          WOLF()              : ANIMAL(150, 200, 2)          {}      };        class CHEETAH : public ANIMAL      {          CHEETAH()              : ANIMAL(75, 125, 5)          {}      };  }; //end CARNIVORE class      //#################################################################  class HERBIVORE : public ANIMAL  {  public:          class RABBIT : public ANIMAL      {          RABBIT()              : ANIMAL(150, 200, 2)          {}      };          class SQUIRREL : public ANIMAL      {          SQUIRREL()              : ANIMAL(150, 200, 2)          {}      };  }; //end HERBIVORE class  

My Problem:

Later down the line, I want to use dynamic_cast to see if one animal is allowed to eat another animal. Specifically, Animal A is only allowed to eat animal B if A is a CARNIVORE and B an HERBIVORE.

Will nesting the classes like I did allow me to check the type of the object later in my programming? I wouldn't want to think this is correct now and have to change it down the line.

Or if there is a better way other than dynamic_cast (a boolean is_carnivore?) should I be using that instead? I'm aiming for the most readable and best OOP practice

Answer by H?vard Nyg?rd for C++ ecosystem simulator (inheritance)


If im correct, you could do something as simple as making each animal have its own level in the ecosystem. Something like this:

class Animal {  Animal(int curr, int max, int rate, int level)...    }  

Then later on make it so the animals can only eat another animal with a lower level.

Something like:

if(animalA.level < animalB.level){      ...  }else{      ...  }  

About the nests however im quite unsure if thats even legal. Never tried to do it like that, and i probably wont.

Answer by Christophe for C++ ecosystem simulator (inheritance)


Your nested classes do not at all represent what you want. Do not consider further this construct to address your problem. Instead:

  • WOLF and CHEETAH should inherit from CARNIVORE
  • SQUIRREL and RABBIT shoulr inherit from HERBIVORE

There are then several ways to see if animal *a can eat animal *b another. The simplest approach would be dynamic_cast as you've suggested:

ANIMAL *a, *b;   ...  if (dynamic_cast(a) && dynamic_cast(b)) {       // *a can eat *b  }  

But this would not be the best OOP practice. I don't know all your constraints and requirements, but if you want to be state of the art and be able to encode much more complex rules (like strength and health of protagonists, exceptions for some species, etc..) you may be interested in implementing some kind of double dispatch (such as discussed here

Answer by Stephen for C++ ecosystem simulator (inheritance)


You already have part of the answer, virtual functions are what you need. You would define a virtual function in your base class called isCarnivore() or isHerbivore() and then create the definition in the derived class to return true or false based on which type the object is.

Example:

class ANIMAL {  public:      virtual bool isHerbivore() = 0; //overload this in your derived class to determine if it is a carnivore      bool isCarnivore() {          return !isHerbivore(); // if its an herbivore it cannot be a carnivore and vice versa      }  };    class CARNIVORE : public ANIMAL {      virtual bool isHerbivore() override {          return false;      }  };    class HERBIVORE : public ANIMAL {      virtual bool isHerbivore() override {          return true;      }  };  

Answer by Chiel for C++ ecosystem simulator (inheritance)


Here you find a running example of my suggestion of two levels of inheritance (which I see has been posted in the meantime as an answer):

#include     struct Animal  {      virtual ~Animal() {};  };  struct Carnivore : public Animal {};  struct Herbivore : public Animal {};  struct Wolf      : public Carnivore {};  struct Cheetah   : public Carnivore {};  struct Squirrel  : public Herbivore {};  struct Rabbit    : public Herbivore {};    bool can_eat(Animal* predator, Animal* prey)  {      return ( dynamic_cast(predator) && dynamic_cast(prey) );  }    int main()  {      Animal* wolf   = new Wolf();      Animal* rabbit = new Rabbit();        std::cout << "Wolf eats rabbit = " << can_eat(wolf, rabbit) << std::endl;      std::cout << "Rabbit eats wolf = " << can_eat(rabbit, wolf) << std::endl;        return 0;  }  

Answer by PaulMcKenzie for C++ ecosystem simulator (inheritance)


You can simply add an attribute to the base class that denotes the food chain hierarchy. For example:

#include   class Animal  {      private:          int a_CUR_food_lvl;           int food_chain_level;          const int a_MAX_food_lvl;           const int a_hunger_rate;        public:          Animal(int curr, int max, int rate, int food_chain)          : a_CUR_food_lvl(curr), a_MAX_food_lvl(max),          a_hunger_rate(rate), food_chain_level(food_chain) {}            bool canEat(Animal& theAnimal) const          { return food_chain_level > theAnimal.food_chain_level; }   //...  };     class Carnivore : public Animal  {     public:          Carnivore(int curr, int max, int rate) : Animal(curr, max, rate, 2) {}  };    class Herbivore : public Animal  {     public:          Herbivore(int curr, int max, int rate) : Animal(curr, max, rate, 1) {}  };    class Insect : public Animal  {     public:          Insect(int curr, int max, int rate) : Animal(curr, max, rate, 0) {}  };    Carnivore Wolf(150, 200, 2);  Carnivore Cheetah(75,125,2);  Herbivore Squirrel(150,200,2);    using namespace std;    int main()  {     cout << (Wolf.canEat(Squirrel)?"true":"false") << endl;     cout << (Squirrel.canEat(Cheetah)?"true":"false") << endl;  }  

Live Example

Note that I used a simple integer, but more than likely, a more sophisticated approach (maybe introduce size as another determining factor to which animal can eat the other animal). As my comment suggested, there are small carnivores that in no way could eat big herbivores.


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.