TDT4102, Spring 2009

Exercise 9

Deadline: 27.03.2009


The objective of this exercise:

General requirements:

Recommended reading:


Introduction

An implementation of the class Shape can be found in the file oving9.zip. Download the file and import it into your project. In Visual C++, this can be achieved by unzipping the file into the project directory. Use  the "add existing file" option to include the files into the project.

Shape is a simple generic class for any kind of geometric two-dimensional shape and it supports information about the color of a shape object and the type of line a shape object has. Both member variables are strings; the color can be a value such as "blue", "yellow", "green", and the line can be a value such as "solid" or "dotted". Please note that the values used for color and line are not very significant.

     class Shape {

   public:
     Shape(string color, string line); //Constructor
     void setColor(string color); //Used to change the color
     void setLine(string line); //Used to change the line type
     string getColor(); //Returns the color
     string getLine();  //Returns the line type
     string toString(); //Returns a string that descibes the shape in this format "Color = blue, Line = dotted"

  private:
     string color;
     string line;
  };


NB! The implementations in this assignement are rather trivial but the main challenge is to understand how inheritance, virtual funtions and plymorphism works.

Part 1: Simple inheritance, Rectangle (20 pt.)


a) Write a class named Rectangle that inherits the Shape class. The Rectangle class is a subtype that extends the Shape class with member variables for width and height and member functions that calculate and return area and circumference. The Rectangle class should include the following member variables and functions.
NB! The constructor for the Rectangle class should use the constructor of the Shape superclass to initialize the color and line member variables.

Part 2: Simple inheritance, Circle (20 pt.)


a) Write a class named Circle that inherits the Shape class. The Circle class that extends Shape with a member variable for radius and functions that calculates and returns area and circumference. The Circle class should include the following member variables and functions.
NB! The constructor for the Circle class should use the constructor of the Shape superclass to initialize the color and line member variables.

Part 3: Three-level inheritance, Square (20 pt.)


a) Write a Square class, which inherits the Rectangle class. Extend the class with the following member function:
NB! The constructor of the Square class should use the constructor of the Rectangle superclass to initialize the member variables. A square has equal sides and the sideLenght argument can be used as both the width and the hight.

Part 4: Redefining the toString() funtion (20 pt.)

a) Redefine the toString() function for all the subclasses that inherits Shape.
NOTE! You should implement the toString() functions in such a way that the redefined functions make use of the toString() function of the parent class!
The toString() function in the Rectangle class should return a string value that is constructed from the value that is returned by the toString() function of the Shape class and additional information that is specific for the Rectangle class.

HINT! The class stringstream can be used to concatenate values of different types into a string.
This class is defined in <sstream> and you typically use the insertion operator << to add data to a stringstream.
The function str() returns the content of a stringstream as a string;

        #include <sstream>      

        stringstream ss;
        ss << "tekst";
        ss << 5;
        string s = ss.str();

Part 5: Virtual functions (20 pt.)

a) The toString() function in the Shape class can be defined as virtual.
Cut and paste the following code into your program. Compile and run the program without declaring the toString() as virtual first. Compile and run the program with the toString() function declared as virtual afterwards.
What is the difference? Make sure you understand why the output is different.

    Shape s1("red", "dotted");
    cout << "s1: " << s1.toString() << endl;
    Rectangle r1("blue", "solid", 6, 6);
    cout << "r1: " <<r1.toString() << endl;
    Shape s2 = r1;
    cout << "s2: " <<s2.toString() << endl;
    Shape *ps1 = new Shape("green", "dotted");
    cout << "ps1: " <<ps1->toString() << endl;
    Rectangle *pr1 = new Rectangle("yellow", "solid", 5, 5);
    cout << "pr1: " << pr1->toString() << endl;
    Shape *ps2 = pr1;
    cout << "ps2: " << ps2->toString() << endl;


b) The Shape class can be made into an abstract class. Instances you make in your program should be of a specific subtype as there are no shape objects without any specific form. Create the following function:
Change the implementation of toString() in the Shape class and include the string from getName() in the final string that is returned.
The toString() function in the Shape class should now be responsible for returning a  string such as this: "Shape =  Rectangle, Color  = blue,  Line = solid"


c) Create a vector that can contain pointers to Shape-objects e.g. 
   vector<Shape *> shapes;
Create some rectangles, squares, circles etc. and add them to the vector (remember that the vector has stores pointers to shapes). Write a simple loop that calls the toString() function on all the shapes in the vector and prints out the returned string. Use the debugger to inspect the sequence of function calls that actually happen for each call to toString().

OPTIONAL: Include the area and circumference in the string that is returned from the toString() function for all shapes. Use pure virtual getArea() and getCircumference functions for this purpose.