CptS 122 – Data Structures
Lab 8: Inheritance in C++
Assigned: Week of
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:
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
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_
const size_t
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_
// hatch to new baby gold fish. yea! The
// total number
of new fish born is the
// current number of fish times BIRTH_
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_
const GoldFish
SAMPLE_FISH(FISH_SIZE, 0, FISH_SIZE *
FRACTION);
{
vector<Plant> moss(MANY_WEEDS, SAMPLE_WEED); // a vector of moss
vector<GoldFish> 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->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_
fish.resize(new_fish_population, SAMPLE_FISH);
}
IV. Submitting Labs:
V. Grading Guidelines: