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 file the 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