Polymorphism Lab
Polymorphism 1
Polymorphism 2
NOTE: start at the top and work your way down following the directions
this lab has things that need to be done in order.
go to your lab directory
copy over the files provided for you ( add the recursive flag -r )
then copy over the Class files from your inheritance homework
assuming that is hw06
cp ../../hw/hw06/Shape.h original/
cp ../../hw/hw06/Line.h original/
cp ../../hw/hw06/Square.h original/
cp ../../hw/hw06/Cube.h original/
cp ../../hw/hw06/Rectangle.h original/
cp ../../hw/hw0r/Rectangular_Prism.h original/
cd into the directory original
if all your classes do not have destructors add them now, the only thing they should do is log the start and end of the function
do not do anything with any of the mains except main5, it will need some work
main1, main2,main3 and main4 are to explain concepts.. look at the main, see what it is doing, run them , look at the output. look at the logs
------
if you run runme1 (main1.cpp) and look at main1.log you should see that when we create an instance of a class both the constructors and the destructors are called for the actual type we are creating as well as those of the base classes
the creation of a Rectangular_Prism object calls all the constructors and destructors of the base classes in the order of inheritance
the constructors are called in this order
first Shape()
then Line()
then Rectangle()
then Rectangular_Prism()
because shape is the base class then line is a child or shape, then rectangle is a child of Line ,then Rectangular_Prism is a child or Rectangle
and the destructors in this order
its backwards from the order the construcors are called
it is VERY important that all the destrucors get called as they may have code to clean up anything created that is specific to that class
first ~Rectangular_Prism()
then ~Rectangle()
then ~Line()
then ~Shape()
LOOK AT THE LOGFILE you should see the constructors and destructors being called
------
if you run runme2 (main2.cpp) you will see that this is the case for all the classes
the constructors and destructors are called for all the base classes
LOOK AT THE LOGFILE you should see the constructors and destructors being called for all the classes
------
runme3 (main3.cpp) uses pointers to the base class to store disparate types of classes, this is Polymorphism
we cant create an array that holds disparate data types, but if they all have the same base class we can store pointers to all the different types.
note that when it runs it does not call the correct ToString functions
since it is pointer to the base class it always calls the ToString functions of the base class
also it only calls the destrucor for the base class (big potential problem)
NOTE: this would work if we use the virtual funtionality.. we will see this work later in the very last part for now we are going to try to make it work without using virtual
we can fix this by casting the pointer to the correct type first
-------
runme4 (main4.cpp)
if we cast the pointer to the correct type it will then call the correct ToString function
take a look at the main and see what we are doing here , we are casting the pointers to the proper type at runtime
NOTE: our problem with the destructors is still in place
-----
main5.cpp
here we have shuffled the array.. we do not know what to cast the pointer to
is it a Shape, Line, Rectangle, Cube??? we don't know... how do we know what type it is so we can cast it to the proper type at runtime.. hey pointer are you a shape,Rectangle, Line???
first copy all your .h files over tothe virtual directory before making any additional changes
we want the .h files there with the destructors we added in step 1 but NOT the changes we are going to make now to the files in the "original" directory
cp *.h ../virtual
now to be able to determine a classes type at runtime
add a public member named shape_type to the Shape class, since it is the base class
all the child classes will inherit it.
in the Shape constructor set it to 0
in the Line constructor set it to 1
in the Square constructor set it to 2
in the Cube constructor set it to 3
in the Rectangle constructor set it to 4
in the Rectangle_Prism constructor set it to 5
you can now identify the type of the class at runtime
and force it to call the proper ToString function
now edit main5.cpp .. it is not complete
in the for loop where you call ToString on each object in the array
use the following logic to cast the pointer to the correct type
if (shapearray[loop]->shape_type == 1)// its a Line
cout << ((Line *)shapearray[loop])->ToString() << endl;
// shapearay[loop] is a shape pointer but cast to Line *
if (shapearray[loop]->shape_type == 5)// its a Rectangular_Prism
cout << ((Rectangular_Prism *)shapearray[loop])->ToString() << endl;
add in tests and casts for all shape_type values 0-5
make these changes to your classes and then main5 should compile and run and you will see that the ToString for each of the 6 classes is called once each
we have not at this point been able to fix the problem with the destructors not being called properly we need virtual functions to accomplish this
-----------------------------------------------------------
now cd into the directory virtual
here we only have main1.cpp and your classes without the most recent changes
instead of adding the shape_type and doing the runtime casting of our pointers we are going to use virtual
make your ToString and descructor function virtual in the base class (Shape.h)
without anychanges at all to the main
it should be able to call the proper ToString function as well as the proper destructor
by making our functions virtual in the base class the compiler added in code to be able to determine at runtime the
propper data type of our pointers and use the correct overloaded function
when you compile and run main1.cpp you will see it action
look at main1.cpp we create an array of pointers to the base class and set each one to a different class type
but when we use a loop and call ToString on the it calls the proper function
also the proper desctructor is called too.
this is Polymorphism in action