CptS 122 – Data Structures                                                                         

 

Lab 8: Inheritance in C++

 

Assigned: Week of October 15, 2012

Due: At the end of the lab session

 

I. Learner Objectives:

 

At the conclusion of this programming assignment, participants should be able to:

 

II. Prerequisites:

 

Before starting this programming assignment, participants should be able to:

 

III. Overview & Requirements:

 

This lab, along with your TA, will help you navigate through designing, implementing, and testing inheritance with classes in C++. It will also help you with understanding how to apply inheritance to an application.

 

Labs are held in a “closed” environment such that you may ask your TA questions. Please use your TAs knowledge to your advantage. You are required to move at the pace set forth by your TA. Please help other students in need when you are finished with a task. You may work in pairs if you wish. However, I encourage you to compose your own solution to each problem. Have a great time! Labs are a vital part to your education in CptS 122 so work diligently.

Tasks:

In this lab you will develop a simulation of a pond where there are several types of life. To do this you will need to develop a base class then inherit from it to create creatures for you pond. Start by building the life class.

 

// DOCUMENTATION for the Life class:

//   The Life class can simulate any growing Life, such as a plant or

//   animal.

//

// CONSTRUCTOR for the Life class:

//   Life(double init_size = 1, double init_rate = 0)

//     Precondition: init_size >= 0. Also, if init_size is 0, then init_rate is

//     also zero.

//     Postcondition: The Life being simulated has been initialized. The

//     value returned from get_size( ) is now init_size (measured in ounces),

//     and the value returned from get_rate( ) is now init_rate (measured in

//     ounces per week).

//

// MODIFICATION MEMBER FUNCTIONS for the Life class:

//   void simulate_week( )

//     Postcondition: The size of the Life has been changed by its current

//     growth rate. If the new size is less than zero, then the actual size is

//     set to zero rather than to a negative value, and the growth rate is also

//     set to zero.

//

//   void assign_rate(double new_rate)

//     Postcondition: The Life's growth rate has been changed to new_rate

//     (measured in ounces per week).

//

//   void alter_size(double amount)

//     Postcondition: The given amount (in ounces) has been added to the

//     Life's current size. If this results in a new size less than zero,

//     then the actual size is set to zero rather than to a negative value, and

//     the growth rate is also set to zero.

//

//   void death( )

//      Postcondition: The Life's current size and growth rate have been

//      set to zero.

//

// CONSTANT MEMBER FUNCTIONS for the Life class:

//   double get_size( ) const

//     Postcondition: The value returned is the Life's current size

//     (in ounces).

//

//   double get_rate( ) const

//     Postcondition: The value returned is the Life's current growth rate

//     (in oz/week).

//

//   bool is_alive( ) const

//     Postcondition: If the current size is greater than zero, then the return

//     value is true; otherwise the return value is false.

 

Task 1.

 

Create a Life.h and Life.cpp file and complete the definition of the Life class described above. Test you Life class with a small main that will declare a lump of Life and simulate its growth for 5 weeks. Start out the lump of life with the declaration

Life  lump(20.0, 10000.0);

After the 5 weeks, reverse the growth rate by -8000 using the assign_rate () method. Continue simulating until the lump of life is dead! Now that you have made life grow and die, let’s move onto a POND OF LIFE. You will create plants and fish and then you can simulate their growth and death over the summer.

 

Task 2.

 

Now it is time to use inheritance to create a few more types of Life. Create two classes, one Plant, one Animal that inherit from Life.  

 

// DOCUMENTATION for the Plant class:

//   Plant is a derived class of the Life class. All the Life public

//   member functions are inherited by a Plant. In addition, a Plant has

//   these extra member functions:

//

// CONSTRUCTOR for the Plant class:

//   Plant(double init_size=0, double init_rate=0)

//     Same as the Life constructor.

//

// MODIFICATION MEMBER FUNCTIONS for the Plant class:

//   void nibbled_on(double amount)

//     Precondition: 0 <= amount <= get_size( ).

//     Postcondition: The size of the plant has been reduced by amount.

//     If this reduces the size to zero, then death is activated.

//

***************************************************************************************************************

 

// DOCUMENTATION for the Animal class:

//   Animal is a derived class of the Life class. All the Life public

//   member functions are inherited by an Animal. In addition, an Animal has

//   these extra member functions:

//

// CONSTRUCTOR for the Animal class:

//   Animal(double init_size=0, double init_rate=0, double init_need=0)

//     Precondition: init_size >= 0, and init_need >= 0. Also, if

//     init_size = 0, then init_rate is also zero.

//     Postcondition: The organism (life) being simulated has been initialized. The

//     value returned from get_size( ) is now init_size (measured in ounces),

//     the value returned from get_rate( ) is now init_rate (measured in ounces

//     per week), and the animal must eat at least init_need ounces of food

//     each week to survive.

//

// MODIFICATION MEMBER FUNCTIONS for the Animal class:

//   void assign_need(double new_need)

//     Precondition: new_need >= 0.

//     Postcondition: The animal's weekly food requirement has been changed to

//     new_need (measured in ounces per week).

//

//   void eat(double amount)

//     Precondition: amount >= 0.

//     Postcondition: The given amount (in ounces) has been added to the amount

//     of food that the animal has eaten this week.

//

//   void simulate_week( ) -- overriden from the Life class

//     Postcondition: The size of the organism (life) has been changed by its current

//     growth rate. If the new size is less than zero, then the actual size is

//     set to zero rather than to a negative value, and the growth rate is also

//     set to zero. Also, if the animal has eaten less than its required need

//     over the past week, then death has been activated.

//

// CONSTANT MEMBER FUNCTIONS for the Animal class:

//   double still_need( ) const

//     Postcondition: The return value is the ounces of food that the animal

//     still needs to survive the current week (i.e., its total weekly need

//     minus the amount that it has already eaten this week.)

//

//   double total_need( ) const

//     Postcondition: The return value is the total amount of food that the

//     animal needs to survive one week (measured in ounces).

//   

 

 

Task 3.

  

OK, one more class and then you can build your very own pond of life. Finish up a Goldfish class described in the bit of commenting below.

 

// DOCUMENTATION for the Goldfish class:

//   Goldfish is a derived class of the Animal class. All the Animal public

//   member functions are inherited by a Goldfish. In addition, a Goldfish has

//   this extra member function:

//

// CONSTRUCTOR for the Goldfish class:

//   Herbivore(double init_size=0, double init_rate=0, double init_need=0)

//     Same as the Animal constructor.

//

// MODIFICATION MEMBER FUNCTIONS for the Goldfish class:

//   void nibble(Plant& meal)

//   Postcondition: eat(amount) and meal.nibbled_on(amount) have both been

//   activated. The amount is usually half of the plant, but it will never be

//   more than 10% of the Goldfish 's weekly need, nor more than the amount that

//   the animal still needs to eat to survive this week.

//

//

// VALUE SEMANTICS for the Life class and its derived classes:

//    Assignments and the copy constructor may be used with all objects.

//

 

 

Task 4.

 

Test your classes with the following main program:

 

#include <iostream>

#include <iomanip>

#include <cstdlib>

#include <vector>

 

#include "Life.h"

#include "pond.h"

 

using std::vector;

using std::cout;

using std::endl;

using std::setw;

using std::setprecision;

 

//  Some Constants for the Pond simulation

 

const size_t   MANY_WEEDS        = 2000;  // number of weeds in the pond

const double   WEED_SIZE         = 15;    // initial size of each weed, in ounces

const double   WEED_RATE         = 2.5;   // growth rate of the weeds

const size_t   INIT_FISH         = 300;   // the initial number of fish in the pond

const double   FISH_SIZE         = 50;    // initial fish size in ounces

const double   FRACTION          = 0.5;   // a fish eats FRACTION of its size each

                                          // week to not die

 

const int      AVERAGE_NIBBLES   = 30;    // average number of plants nibbled on by a fish

                                          // each week

 

const double   BIRTH_RATE        = 0.05;  // at the end of each week, some fish eggs

                                          // hatch to new baby gold fish. yea! The

                                          // total number of new fish born is the

                                          // current number of fish times BIRTH_RATE

 

void pondWeek( vector<GoldFish>&  fishes, vector<Plant>&  mosses);

double total_mass(const vector<Plant>&  stuff);

 

// examples to start the simulation with

const Plant SAMPLE_WEED(WEED_SIZE, WEED_RATE);

const GoldFish SAMPLE_FISH(FISH_SIZE, 0, FISH_SIZE * FRACTION);

 

 void main (void)

{

   vector<Plant> moss(MANY_WEEDS, SAMPLE_WEED);    // a vector of moss

   vector<GoldFish> fish(INIT_FISH, SAMPLE_FISH);  // a vector of fish

 

   int numberWeeks = 32;

   int i;

 

   cout << "Week      Number      Moss Mass" << endl;

 

   for (int i = 0; i < numberWeeks; i++)

   {

      pondWeek(fish, moss);

      cout << setw(4) << i;

      cout << setw(10) << fish.size();

      cout << setw(14) << setprecision(0) << total_mass(moss);

      cout << endl;

   }

}

 

double total_mass(const vector<Plant>& weed)

{

   double answer = 0.0;

 

   for (int i = 0; i < weed.size(); i++)

   {

      answer += weed[i].get_size();

   }

   return answer;

}

 

void pondWeek(vector<GoldFish>& fish, vector<Plant>& moss)

{

   vector<Plant>::iterator       wi;

   vector<Plant>::size_type      weed_index;

 

   vector<GoldFish>::iterator    fi;

   vector<GoldFish>::size_type   fish_index;

   vector<GoldFish>::size_type   new_fish_population;

 

   int many_iteration = AVERAGE_NIBBLES * fish.size();

 

   // fish swim around and chomp on plants. sort of a random process.

   for (int i = 0; i < many_iteration; i++)

   {

      fish_index  = rand() % fish.size();

      weed_index  = rand() % moss.size();

      fish[fish_index].nibble(moss[weed_index]);

   }

 

   // so what happens to the plants

   for (wi = moss.begin(); wi != moss.end(); wi++)

   {

      wi->simulate_week();

   }

 

   // and what happens to the fishies

 

   fi = fish.begin();   // this is a vector iterator CS 223 :)

   while (fi != fish.end())

   {

      fi->simulate_week();

      if(!fi->is_alive())

      {

         fish.erase(fi);

      }

      else

      {

         fi++;

      }

   }

 

   new_fish_population = (1 + BIRTH_RATE) * fish.size();

   fish.resize(new_fish_population, SAMPLE_FISH);

}

 

IV. Submitting Labs:

 

V. Grading Guidelines: