Lessons Home

Polymorphism and Abstraction

 

Polymorphism

In an inheritance scenario, a parent class is configured to provide its child with the basic foundation the child needs. Although a child can implement a new behavior not available on the parent object, sometimes a child object will need a customized implementation of a behavior that has already been configured with its parent. That is what happens for example when inheriting a sphere from a circle class. Both have a characteristic called Area but the area is calculated differently on each shape.

Inheritance Review

  1. Create a new C++ Console Application in a folder called Polymorphism
  2. Save the first file as Main and the project as Polymorphism
  3. Add a new class and save it as Circle
  4. Create a TCircle class in the Circle.h file as follows:
     
    //---------------------------------------------------------------------------
    
    #ifndef CircleH
    
    #define CircleH
    
    //---------------------------------------------------------------------------
    
    class TCircle
    
    {
    
    public:
    
        TCircle(double r = 0.00);
    
        ~TCircle();
    
        void setRadius(const double r) { Radius = r; }
    
        double getRadius() const { return Radius; }
    
        double Area() const;
    
        void ShowCharacteristics() const;
    
    protected:
    
        double Radius;
    
    };
    
    //---------------------------------------------------------------------------
    
    #endif
  5. Implement the TCircle class in the Circle.cpp file as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iomanip>
    
    using namespace std;
    
    #include "Circle.h"
    
    //---------------------------------------------------------------------------
    
    const double PI = 3.14159;
    
    //---------------------------------------------------------------------------
    
    TCircle::TCircle(double r)
    
        : Radius(r)
    
    {
    
    }
    
    //---------------------------------------------------------------------------
    
    TCircle::~TCircle()
    
    {
    
    }
    
    //---------------------------------------------------------------------------
    
    double TCircle::Area() const
    
    {
    
        return Radius * Radius * PI;
    
    }
    
    //---------------------------------------------------------------------------
    
    void TCircle::ShowCharacteristics() const
    
    {
    
        cout << "Circle Characteristics"; 
    
        cout << setiosflags(ios::fixed) << setprecision(2);
    
        cout << "\nRadius: " << getRadius();
    
        cout << "\nArea: " << Area();
    
    }
    
    //---------------------------------------------------------------------------
  6. Add a new class and save it as Sphere
  7. To create a new TSphere class based on the TCircle class, lay its foundation in the Sphere.h file as follows:
     
    //---------------------------------------------------------------------------
    
    #ifndef SphereH
    
    #define SphereH
    
    #include "Circle.h"
    
    //---------------------------------------------------------------------------
    
    class TSphere : public TCircle
    
    {
    
    public:
    
        TSphere(double x);
    
        ~TSphere() {}
    
        double Area() const;
    
        double Volume() const;
    
        void ShowCharacteristics() const;
    
    private:
    
    };
    
    //---------------------------------------------------------------------------
    
    #endif
  8. Implement the new class as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iomanip>
    
    using namespace std;
    
    #include "Sphere.h"
    
    //---------------------------------------------------------------------------
    
    const double PI = 3.14159;
    
    //---------------------------------------------------------------------------
    
    TSphere::TSphere(double n)
    
        : TCircle(n)
    
    {
    
    }
    
    //---------------------------------------------------------------------------
    
    double TSphere::Area() const
    
    {
    
        return 4 * PI * Radius * Radius;
    
    }
    
    //---------------------------------------------------------------------------
    
    double TSphere::Volume() const
    
    {
    
        return 4 * PI * Radius * Radius * Radius / 3;
    
    }
    
    //---------------------------------------------------------------------------
    
    void TSphere::ShowCharacteristics() const
    
    {
    
        cout << "Circle Characteristics"; 
    
        cout << setiosflags(ios::fixed) << setprecision(2);
    
        cout << "\nRadius: " << getRadius();
    
        cout << "\nArea: " << Area();
    
        cout << "\nVolume: " << Volume();
    
    }
    
    //---------------------------------------------------------------------------
  9. To inherit another class, add a new class and save it as Cylinder
  10. Create the TCylinder class based on TCircle in the Cylinder.h file as follows:
     
    //---------------------------------------------------------------------------
    
    #ifndef CylinderH
    
    #define CylinderH
    
    #include "Circle.h"
    
    //---------------------------------------------------------------------------
    
    class TCylinder : public TCircle
    
    {
    
    public:
    
        TCylinder(double r, double h);
    
        ~TCylinder() {}
    
        void setHeight(const double h) { Height = h; }
    
        double getHeight() const { return Height; }
    
        double BaseArea() const;
    
        double LateralArea() const;
    
        double Area() const;
    
        double Volume() const;
    
        void ShowCharacteristics() const;
    
    private:
    
        double Height;
    
    };
    
    //---------------------------------------------------------------------------
    
    #endif
  11. Implement the new class in its source file as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iomanip>
    
    using namespace std;
    
    
    
    #include "Cylinder.h"
    
    //---------------------------------------------------------------------------
    
    const double PI = 3.14159;
    
    //---------------------------------------------------------------------------
    
    TCylinder::TCylinder(double x, double y)
    
        : TCircle(x), Height(y)
    
    {
    
    }
    
    //---------------------------------------------------------------------------
    
    double TCylinder::BaseArea() const
    
    {
    
        return TCircle::Area();
    
    }
    
    //---------------------------------------------------------------------------
    
    double TCylinder::LateralArea() const
    
    {
    
        double Circ = Radius * 2 * PI;
    
        return Circ * Height;
    
    }
    
    //---------------------------------------------------------------------------
    
    double TCylinder::Area() const
    
    {
    
        double Base = TCircle::Area();
    
        double Lateral = LateralArea();
    
        return (2 * Base) + Lateral;
    
    }
    
    //---------------------------------------------------------------------------
    
    double TCylinder::Volume() const
    
    {
    
        double Base = TCircle::Area();
    
        return Base * Height;
    
    }
    
    //---------------------------------------------------------------------------
    
    void TCylinder::ShowCharacteristics() const
    
    { 
    
        cout << "Circle Characteristics";
    
        cout << setiosflags(ios::fixed) << setprecision(2);
    
        cout << "\nRadius: " << getRadius();
    
        cout << "\nHeight: " << getHeight();
    
        cout << "\nBase Area: " << BaseArea();
    
        cout << "\nLateral Area: " << LateralArea();
    
        cout << "\nArea: " << Area();
    
        cout << "\nVolume: " << Volume();
    
    }
    
    //---------------------------------------------------------------------------
  12. To prepare a test, change the main() function in the Main.cpp file as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    using namespace std;
    
    //---------------------------------------------------------------------------
    
    #include "Circle.h"
    
    #include "Sphere.h"
    
    #include "Cylinder.h"
    
    
    
    
    
    int main(int argc, char* argv[])
    
    {
    
        TCircle e(12.55);
    
        TSphere s(22.25);
    
        TCylinder c(34.05, 28.35);
    
    
    
        e.ShowCharacteristics();
    
        cout << "\n\n";
    
        s.ShowCharacteristics();
    
        cout << "\n\n";
    
        c.ShowCharacteristics();
    
    
    
        
    
        
    
        return 0;
    
    }
    
    //---------------------------------------------------------------------------
  13. To test the program, press F9.
  14. We can also dynamically declare the objects and access them as pointers. To see an example, change the main() function as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    using namespace std;
    
    //---------------------------------------------------------------------------
    
    #include "Circle.h"
    
    #include "Sphere.h"
    
    #include "Cylinder.h"
    
    
    
    
    
    int main(int argc, char* argv[])
    
    {
    
        TCircle *e = new TCircle(12.55);
    
        TSphere *s = new TSphere(16.15);
    
        TCylinder *c = new TCylinder(14.25, 10.85);
    
    
    
        e->ShowCharacteristics();
    
        cout << "\n\n";
    
        s->ShowCharacteristics();
    
        cout << "\n\n";
    
        c->ShowCharacteristics();
    
    
    
        
    
        
    
        return 0;
    
    }
    
    //---------------------------------------------------------------------------
  15. Test the program.
     
    When studying inheritance, we learned that there is a special bond between an inherited class and its parent. Not only does the child object have access to the public members of a class but also the child, based on this relationship, has direct access to the members of the protected section (the child is a protégé) of the parent. The program above shows us that, in order to access a class’ members, we can just declare an instance of the class and use either the member access operator “.” or the pointer access operator “->”.
     
    If there is such a good relationship between a class and its children, is it possible to access a member of a child object using an instance of the parent? We will declare only an instance of the parent class, TCircle, and try to access its child using such a variable.
  16. Change the main() function as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    using namespace std;
    
    //---------------------------------------------------------------------------
    
    #include "Circle.h"
    
    #include "Sphere.h"
    
    #include "Cylinder.h"
    
    
    
    
    
    int main(int argc, char* argv[])
    
    {
    
        TSphere *s = new TSphere(15.32);
    
        TCylinder *c = new TCylinder(36.08, 20.24);
    
    
    
        TCircle *e = s;
    
        e->ShowCharacteristics();
    
        cout << "\n\n";
    
        e = c;
    
        e->ShowCharacteristics();
    
    
    
        
    
        
    
        return 0;
    
    }
    
    //---------------------------------------------------------------------------
  17. Test the program.
    Notice that, although the pointer variable *e has been initialized with variables *s and *c, only the characteristics of the circle are displayed.

Virtual Functions

A virtual function is a function that makes sure that, in an inheritance scenario, the right function is called regardless of the expression that calls the function. The last three classes we have used have two functions called Area() and ShowCharacteristics() each. Let us consider the member function ShowCharacteristics() that is present in all three classes. If we need an instance of the parent class to call the right member function, in this case Area, we must declare ShowCharacteristics () in the parent class as virtual.

Declaring a Virtual Function

  1. Click the Circle.h tab and change the declaration of the Area() function as follows:
     
    //---------------------------------------------------------------------------
    
    #ifndef CircleH
    
    #define CircleH
    
    //---------------------------------------------------------------------------
    
    class TCircle
    
    {
    
    public:
    
        TCircle(double r = 0.00);
    
        ~TCircle();
    
        void setRadius(const double r) { Radius = r; }
    
        double getRadius() const { return Radius; }
    
        double Area() const;
    
        virtual void ShowCharacteristics() const;
    
    protected:
    
        double Radius;
    
    };
    
    //---------------------------------------------------------------------------
    
    #endif
  2. Test the program again. Notice that, this time, even though an instance of the TCircle class made the call, the characteristics of the assigned variables display.
  3. Return to your programming environment.
  4. Since the Area() function is present on the parent as well as the inherited classes, make it virtual in the base class as follows:
     
    //---------------------------------------------------------------------------
    
    #ifndef CircleH
    
    #define CircleH
    
    //---------------------------------------------------------------------------
    
    class TCircle
    
    {
    
    public:
    
        TCircle(double r = 0.00);
    
        ~TCircle();
    
        void setRadius(const double r) { Radius = r; }
    
        double getRadius() const { return Radius; }
    
        virtual double Area() const;
    
        virtual void ShowCharacteristics() const;
    
    protected:
    
        double Radius;
    
    };
    
    //---------------------------------------------------------------------------
    
    #endif
  5. Test the program. Notice that the right functions, as far as their having been assigned to the base class instance goes, are called.
    Even though you can use polymorphism to help the compiler identify which function is being called, if you want to access the same function of the base class, you can qualify it with the scope resolution operator “::”.

    As you can see, a function with the same name can be declared in both a base and a derived classes. This allows a derived class to define its custom definition of the function. Because the derived class “re-writes” the same function, the derived class is said to override the function. A function can be overridden only if it is virtual. A function can be virtual only if carries the same name, the same return type, and the same type(s) of argument(s) if any.

Virtual Destructors

Consider a case where you have created a class that is derived from another class. When you dynamically call the inherited class using an instance of the base class (as done in the last example), during the closing of the program, the destructor of the child class is called first, followed by the destructor of the base class. If you dynamically declare an instance of the base class and then invoke the children of the class, you need to make sure that each destructor and the right destructor of the classes that was used is called to destroy the class; this is safe measure to avoid memory leak. This aspect of C++ programming is taken care of by declaring the destructor of the base class as virtual. Whenever the destructor of the parent class is declared virtual, the destructor of an inherited class is also virtual. This ensures that, the program closes, all of the destructors of the base class and its children that were used are called, providing a safe claim of the memory that was used.

To declare a destructor as virtual, type the virtual keyword on its left, in the body of the class. Here is an example:

//---------------------------------------------------------------------------

#ifndef CircleH

#define CircleH

//---------------------------------------------------------------------------

class TCircle

{

public:

    TCircle(double r = 0.00);

    virtual ~TCircle();

    void setRadius(const double r) { Radius = r; }

    double getRadius() const { return Radius; }

    double Area() const;

    virtual void ShowCharacteristics() const;

protected:

    double Radius;

};

//---------------------------------------------------------------------------

#endif

Abstract Classes

An abstract class is a class whose role is only meant to lay a foundation for those classes that would need a common behavior or similar characteristics. Therefore, an abstract class is used only as a base class for inheritance. A class is made abstract by declaring at least one its member functions as a “pure” virtual function.

Only a virtual function can be made “pure”. The syntax of declaring a pure function is:

virtual ReturnType FunctionName() = 0;

The virtual keyword is required to make sure that a (any) child of this class can implement this function as it deems fit. The ReturnType is the data type that the function will return. The FunctionName is an appropriate name for the function. The = 0 is required. It lets the compiler know that this function is a pure virtual function.

When a function has been declared as pure virtual, you do not need to implement it. Instead, each inherited class of an abstract class must provide its own implementation of the pure member function.

When creating an abstract class, you can declare all of its member functions as pure. Here is an example:

//---------------------------------------------------------------------------

struct TTent

{

    virtual int WhatIsTheCapacity() = 0;

    virtual double TentArea() = 0;

    virtual double TentVolume() = 0;

    virtual char* TextureColor() = 0;

};

//---------------------------------------------------------------------------

In this case, the class does not need a source file or any implementation because none of its member functions will be implemented.

An abstract base class can also have a mix of pure and non-pure functions. Here is an example:

//---------------------------------------------------------------------------

struct TTent

{

    virtual int WhatIsTheCapacity() = 0;

    virtual double TentArea() = 0;

    virtual double TentVolume() = 0;

    virtual char* TextureColor() = 0; // Pure virtual function

    virtual char* TextureName(); // Virtual function

    int ShapeType(); // Regular member function

};

//---------------------------------------------------------------------------

In this case, as we have done with the other classes so far, you must implement the non-pure functions in the base and let the inherited classes implement their own version(s) of the pure virtual function(s).

Implementing Abstract Classes

  1. Create a new C++ Console Application and save it in a folder called Polygons
  2. Save the class as Main and the project as RegPolygons
  3. Add a new class and save it as Polygon
  4. On the Status Bar, click the Polygon.h tab and create a regular class as follows:
     
    //---------------------------------------------------------------------------
    
    #ifndef PolygonH
    
    #define PolygonH
    
    //---------------------------------------------------------------------------
    
    namespace Shapes
    
    {
    
    class TPolygon
    
    {
    
    public:
    
        TPolygon(int s = 0, char *n = "", double r = 0.00);
    
        virtual ~TPolygon();
    
        void setNbrOfSides(const int n);
    
        int getNbrOfSides() const { return NbrOfSides; }
    
        void setPolyName(const char *n);
    
        char * getPolyName() const { return PolyName; }
    
        void setRadius(const double r);
    
        double getRadius() const { return Radius; }
    
        double CentralAngle() const;
    
        double InteriorAngle() const;
    
        protected:
    
        int NbrOfSides;
    
        char *PolyName;
    
        double Radius;
    
    };
    
    }
    
    //---------------------------------------------------------------------------
    
    #endif
  5. Click the Polygon.cpp tab and implement the member functions as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    using namespace std;
    
    #include "Polygon.h"
    
    //---------------------------------------------------------------------------
    
    
    
    //---------------------------------------------------------------------------
    
    namespace Shapes
    
    {
    
    TPolygon::TPolygon(int s, char *n, double r)
    
    {
    
        //TODO: Add your source code here
    
        NbrOfSides = s;
    
        Radius = r;
    
        setPolyName(n);
    
    }
    
    //---------------------------------------------------------------------------
    
    TPolygon::~TPolygon()
    
    {
    
        //TODO: Add your source code here
    
        delete [] PolyName;
    
    }
    
    //---------------------------------------------------------------------------
    
    void TPolygon::setNbrOfSides(const int n)
    
    {
    
        // Avoid a negative number of sides. It wouldn't make sense.
    
        // This program considers only regular polygons.
    
        // The minimum number of sides is 3, which corresponds to an
    
        // equilateral triangle
    
        if( n < 3 )
    
            NbrOfSides = 0;
    
        else if( n < 4 )
    
            NbrOfSides = 3; // Equilateral Triangle
    
        else if( n == 4 )
    
            NbrOfSides = 4; // Square
    
        else if( n == 5 )
    
            NbrOfSides = 5; // Pentagon
    
        else if( n == 6 )
    
            NbrOfSides = 6; // Hexagon
    
        else if( n == 7 || n == 8 )
    
            NbrOfSides = 8; // Octagon
    
        else if( n == 9 || n == 10 )
    
            NbrOfSides = 10;// Decagon
    
        else //if( n == 11 || n == 12 )
    
            NbrOfSides = 12;// Dodecagon
    
    }
    
    //---------------------------------------------------------------------------
    
    void TPolygon::setPolyName(const char * n)
    
    {
    
        //TODO: Add your source code here
    
        PolyName = new char[strlen(n) + 1];
    
        strcpy(PolyName, n);
    
    }
    
    //---------------------------------------------------------------------------
    
    void TPolygon::setRadius(const double r)
    
    {
    
        //Avoid a negative radius. It wouldn't make sense
    
        if( r < 0 )
    
            Radius = 0.00;
    
        else
    
            Radius = r;
    
    }
    
    //---------------------------------------------------------------------------
    
    double TPolygon::CentralAngle() const
    
    {
    
        return 360 / NbrOfSides;
    
    }
    
    //---------------------------------------------------------------------------
    
    double TPolygon::InteriorAngle() const
    
    {
    
        return (NbrOfSides - 2) * 180 / NbrOfSides;
    
    }
    
    //---------------------------------------------------------------------------
    
    }
    
    //---------------------------------------------------------------------------
  6. Prepare the main() function for a test as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    #include <iomanip>
    
    using namespace std;
    
    //---------------------------------------------------------------------------
    
    #include "Polygon.h"
    
    
    
    int main(int argc, char* argv[])
    
    {
    
        Shapes::TPolygon *Pol = new Shapes::TPolygon;
    
        Pol->setRadius(15.55);
    
        Pol->setNbrOfSides(25);
    
        Pol->setPolyName("Unknown");
    
    
    
        cout << "Shape Characteristics";
    
        cout << setiosflags(ios::fixed) << setprecision(2);
    
        cout << "\nName: " << Pol->getPolyName();
    
        cout << "\nSides: " << Pol->getNbrOfSides();
    
        cout << "\nRadius: " << Pol->getRadius();
    
        cout << "\nCentral Angle: " << Pol->CentralAngle() << "*";
    
        cout << "\nInterior Angle: " << Pol->InteriorAngle();
    
    
    
        
    
        
    
        return 0;
    
    }
    
    //---------------------------------------------------------------------------
  7. Test the program. Return to your programming environment.
  8. To add some pure virtual function and qualify the class as abstract, change the TPolygon class creation as follows:
     
    //---------------------------------------------------------------------------
    
    #ifndef PolygonH
    
    #define PolygonH
    
    //---------------------------------------------------------------------------
    
    namespace Shapes
    
    {
    
    class TPolygon
    
    {
    
    public:
    
        TPolygon(int s = 0, char *n = "", double r = 0.00);
    
        virtual ~TPolygon();
    
        void setNbrOfSides(const int n);
    
        int getNbrOfSides() const { return NbrOfSides; }
    
        void setPolyName(const char *n);
    
        char * getPolyName() const { return PolyName; }
    
        void setRadius(const double r);
    
        double getRadius() const { return Radius; }
    
        double CentralAngle() const;
    
        double InteriorAngle() const;
    
        virtual double Side() = 0;
    
        virtual double Apothem() = 0;
    
        virtual double Perimeter() = 0;
    
        double Area();
    
        virtual void ShapeCharacteristics() = 0; 
    
    protected:
    
        int NbrOfSides;
    
        char *PolyName;
    
        double Radius;
    
    };
    
    }
    
    //---------------------------------------------------------------------------
    
    #endif
  9. To implement the newly added Area() member function, add it to the Polygon.cpp file as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    using namespace std;
    
    #include "Polygon.h"
    
    //---------------------------------------------------------------------------
    
    
    
    //---------------------------------------------------------------------------
    
    namespace Shapes
    
    {
    
    TPolygon::TPolygon(int s, char *n, double r)
    
    {
    
        . . .
    
    }
    
    //---------------------------------------------------------------------------
    
    . . .
    
    //---------------------------------------------------------------------------
    
    double TPolygon::Area()
    
    {
    
        double p = Perimeter();
    
        double r = Apothem();
    
        return p * r / 2;
    
    }
    
    //---------------------------------------------------------------------------
    
    }
    
    //---------------------------------------------------------------------------
  10. To test the program, press F9.
  11. Read the errors that you receive. As you can see, you are not allowed to declare an instance of an abstract class:
  12. Return to your programming environment.
  13. Add a new class and save it as Triangle
  14. In the Triangle.h file, derive a new TTriangle class from the TPolygon class as follows:
     
    //---------------------------------------------------------------------------
    
    #ifndef TriangleH
    
    #define TriangleH
    
    #include "Polygon.h"
    
    //---------------------------------------------------------------------------
    
    class TTriangle : public Shapes::TPolygon
    
    {
    
    public:
    
        // We use two constructors so that the user can initialize
    
        // either by not specifying anything or by providing the radius
    
        TTriangle();
    
        TTriangle(double r);
    
        ~TTriangle();
    
        virtual double Side();
    
        virtual double Apothem();
    
        virtual double Perimeter();
    
        double Height();
    
        virtual void ShapeCharacteristics();
    
    protected:
    
    private:
    
    };
    
    //---------------------------------------------------------------------------
    
    #endif
  15. Implement the class in the Triangle.cpp source file as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    #include <iomanip>
    
    #include <math.h>
    
    using namespace std;
    
    
    
    #include "Triangle.h"
    
    //---------------------------------------------------------------------------
    
    
    
    //---------------------------------------------------------------------------
    
    TTriangle::TTriangle()
    
    {
    
        // If the constructor is empty, at least we know the number of sides
    
        // and the name of this polygon
    
        setNbrOfSides(3);
    
        setPolyName("Equilateral Triangle");
    
        setRadius(getRadius());
    
    }
    
    //---------------------------------------------------------------------------
    
    TTriangle::TTriangle(double r)
    
    {
    
        setNbrOfSides(3);
    
        setPolyName("Equilateral Triangle");
    
        setRadius(r);
    
    }
    
    //---------------------------------------------------------------------------
    
    TTriangle::~TTriangle()
    
    {
    
    }
    
    //---------------------------------------------------------------------------
    
    double TTriangle::Side()
    
    {
    
        return Radius * sqrt(3);
    
    }
    
    //---------------------------------------------------------------------------
    
    double TTriangle::Apothem()
    
    {
    
        return Radius / 2;
    
    }
    
    //---------------------------------------------------------------------------
    
    double TTriangle::Perimeter()
    
    {
    
        double S = Side();
    
        return 3 * S;
    
    }
    
    //---------------------------------------------------------------------------
    
    double TTriangle::Height()
    
    {
    
        return Apothem() + Radius;
    
    }
    
    //---------------------------------------------------------------------------
    
    void TTriangle::ShapeCharacteristics()
    
    {
    
        cout << "Shape Characteristics";
    
        cout << "\nName: " << getPolyName();
    
        cout << "\nSides: " << getNbrOfSides();
    
        cout << "\nRadius: " << getRadius();
    
        cout << "\nCentral Angle: " << CentralAngle();
    
        cout << "\nInterior Angle: " << InteriorAngle();
    
        cout << setiosflags(ios::fixed) << setprecision(2);
    
        cout << "\nApothem: " << Apothem();
    
        cout << "\nHeight: " << Height();
    
        cout << "\nPerimeter: " << Perimeter();
    
        cout << "\nArea: " << Area();
    
    }
    
    //---------------------------------------------------------------------------
  16. To prepare a test, change the Main.cpp file as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    using namespace std;
    
    //---------------------------------------------------------------------------
    
    #include "Triangle.h"
    
    
    
    int main(int argc, char* argv[])
    
    {
    
        TTriangle *Tri = new TTriangle;
    
    
    
        Tri->setRadius(15.55);
    
        Tri->ShapeCharacteristics();
    
    
    
        
    
        
    
        return 0;
    
    }
    
    //---------------------------------------------------------------------------
  17. Test the program and return to your programming environment.
  18. Add a new class and save it as Square
  19. In the Square.h file, create a regular polygon of a square based on the TPolygon class as follows:
     
    //---------------------------------------------------------------------------
    
    #ifndef SquareH
    
    #define SquareH
    
    #include "Polygon.h"
    
    //---------------------------------------------------------------------------
    
    class TPolySquare : public Shapes::TPolygon
    
    {
    
    public:
    
        TPolySquare();
    
        TPolySquare(double r);
    
        ~TPolySquare() {}
    
        virtual double Side();
    
        virtual double Apothem();
    
        virtual double Perimeter();
    
        virtual void ShapeCharacteristics();
    
    protected:
    
    private:
    
    };
    
    //---------------------------------------------------------------------------
    
    #endif
  20. Implement the TPolySquare class as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    #include <iomanip>
    
    #include <math.h>
    
    using namespace std;
    
    //---------------------------------------------------------------------------
    
    
    
    #include "Square.h"
    
    
    
    //---------------------------------------------------------------------------
    
    TPolySquare::TPolySquare()
    
    {
    
        // If the constructor is empty, at least we know the number of sides
    
        // and the name of this polygon
    
        setNbrOfSides(4);
    
        setPolyName("Square");
    
        setRadius(getRadius());
    
    }
    
    //---------------------------------------------------------------------------
    
    TPolySquare::TPolySquare(double r)
    
    {
    
        setNbrOfSides(4);
    
        setPolyName("Square");
    
        setRadius(r);
    
    }
    
    //---------------------------------------------------------------------------
    
    double TPolySquare::Side()
    
    {
    
        return Radius * sqrt(2);
    
    }
    
    //---------------------------------------------------------------------------
    
    double TPolySquare::Apothem()
    
    {
    
        return sqrt(2) * Radius / 2;
    
    }
    
    //---------------------------------------------------------------------------
    
    double TPolySquare::Perimeter()
    
    {
    
        double S = Side();
    
        return 4 * S;
    
    }
    
    //---------------------------------------------------------------------------
    
    void TPolySquare::ShapeCharacteristics()
    
    {
    
        cout << "Shape Characteristics";
    
        cout << "\nName: " << getPolyName();
    
        cout << "\nSides: " << getNbrOfSides();
    
        cout << "\nRadius: " << getRadius();
    
        cout << setiosflags(ios::fixed) << setprecision(0);
    
        cout << "\nCentral Angle: " << CentralAngle();
    
        cout << "\nInterior Angle: " << InteriorAngle();
    
        cout << setiosflags(ios::fixed) << setprecision(2);
    
        cout << "\nApothem: " << Apothem();
    
        cout << "\nPerimeter: " << Perimeter();
    
        cout << "\nArea: " << Area();
    
    }
    
    //---------------------------------------------------------------------------
  21. Add a new class and save it as Hexagon
  22. Create a THexagon object derived from the TPolygon class as follows:
      
    //---------------------------------------------------------------------------
    
    #ifndef HexagonH
    
    #define HexagonH
    
    #include "Polygon.h"
    
    //---------------------------------------------------------------------------
    
    class THexagon : public Shapes::TPolygon
    
    {
    
    public:
    
        THexagon();
    
        THexagon(double r);
    
        ~THexagon() {}
    
        virtual double Side();
    
        virtual double Apothem();
    
        virtual double Perimeter();
    
        virtual void ShapeCharacteristics();
    
    protected:
    
    private:
    
    };
    
    //---------------------------------------------------------------------------
    
    #endif
  23. Implement the THexagon class as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    #include <iomanip>
    
    #include <math.h>
    
    using namespace std;
    
    #include "Hexagon.h"
    
    
    
    //---------------------------------------------------------------------------
    
    THexagon::THexagon()
    
    {
    
        // If the constructor is empty, at least we know the number of sides
    
        // and the name of this polygon
    
        setNbrOfSides(6);
    
        setPolyName("Hexagon");
    
        setRadius(getRadius());
    
    }
    
    //---------------------------------------------------------------------------
    
    THexagon::THexagon(double r)
    
    {
    
        setNbrOfSides(6);
    
        setPolyName("Hexagon");
    
        setRadius(r);
    
    }
    
    //---------------------------------------------------------------------------
    
    double THexagon::Side()
    
    {
    
        return Radius;
    
    }
    
    //---------------------------------------------------------------------------
    
    double THexagon::Apothem()
    
    {
    
        return sqrt(3) * Radius / 2;
    
    }
    
    //---------------------------------------------------------------------------
    
    double THexagon::Perimeter()
    
    {
    
        double S = Side();
    
        return 6 * S;
    
    }
    
    //---------------------------------------------------------------------------
    
    void THexagon::ShapeCharacteristics()
    
    {
    
        cout << "Shape Characteristics";
    
        cout << "\nName: " << getPolyName();
    
        cout << "\nSides: " << getNbrOfSides();
    
        cout << "\nRadius: " << getRadius();
    
        cout << setiosflags(ios::fixed) << setprecision(0);
    
        cout << "\nCentral Angle: " << CentralAngle();
    
        cout << "\nInterior Angle: " << InteriorAngle();
    
        cout << setiosflags(ios::fixed) << setprecision(2);
    
        cout << "\nApothem: " << Apothem();
    
        cout << "\nPerimeter: " << Perimeter();
    
        cout << "\nArea: " << Area();
    
    }
    
    //---------------------------------------------------------------------------
  24. Before testing the program, change the Main.cpp file as follows:
     
    //---------------------------------------------------------------------------
    
    #include <iostream>
    
    using namespace std;
    
    //---------------------------------------------------------------------------
    
    #include "Triangle.h"
    
    #include "Square.h"
    
    #include "Hexagon.h"
    
    
    
    //---------------------------------------------------------------------------
    
    int main(int argc, char* argv[])
    
    {
    
        TTriangle *Tri = new TTriangle;
    
        Tri->setRadius(15.55);
    
        Tri->ShapeCharacteristics();
    
    
    
        cout << "\n\nNew Shape";
    
        
    
        TPolySquare *Sq = new TPolySquare(22.36);
    
        Sq->ShapeCharacteristics();
    
    
    
        cout << "\n\nNew Shape";
    
        
    
        clrscr();
    
        THexagon *Hx = new THexagon;
    
        Hx->setRadius(36.08);
    
        Hx->ShapeCharacteristics();
    
    
    
        return 0;
    
    }
    
    //---------------------------------------------------------------------------
  25. Test the program and return to your programming environment

 

 

 

Value Casting

 

Introduction

We have been introduced to declaring variables using specific data types. After declaring a value and initializing it, you may want the value to change type without redefining it. This is required in some cases where you already have a value, probably produced by one variable, while another variable declared with a different data type. This means that you would need to convert a value from one type into another type. For example, you may have declared a variable using a double data type but you need the value of that variable to be used as an int. Transferring a value from one type to another is referred to as casting.

There are two broad types of casting available in C++: C's old school of casting and the C++ standards.

 

C How To Cast a Value

C, the parent of C++ supports value casting by specifying the type of value you want an existing one to have. To do this, you use the following formula:

(DataType)Expression

Based on this formula, in the parentheses, enter the type of data you want the existing or resulting value to have. The DataType factor can be any of the data types we saw above. The Expression factor can be a constant value. Here is an example:

#include <iostream>

using namespace std;



int main()

{

	cout << "Number: " << (int)3.14159 << "\n";



	return 0;

}

Notice that the value to convert is a floating-point number. If the conversion is successful, the new value would be conform to the type in parentheses. For example, the above code would produce:

Number: 3

Here is another version of the above program:

#include <iostream>

using namespace std;



int main()

{

	int number;



	number = (int)3.14159;

	cout << "Number: " << number << "\n";



	return 0;

}

The Expression factor can also be the result of a calculation. In this case, you should include the whole expression is its own parentheses.

The Expression factor of our formula can also be the name of a variable that holds a value. Here is an example:

#include <iostream>

using namespace std;



int main()

{

	double price = 258.85;

	int number;



	cout << "Price? $" << price << "\n";



	number = (int)price;

	cout << "Number: " << number << "\n";



	return 0;

}

This would produce:

Price? $258.85

Number: 258
 

C++ Casting

C++ provides its own support of value casting using variable keywords so you can specify the type of conversion you want. One of the keywords used is static_cast and the formula is:

static_cast<DataType>(Expression)

In this formula, the static_cast keyword, the <, the >, and the parentheses are required. The DataType factor should be an existing data type such as those we have reviewed in this lesson. The Expression factor can be a constant value. Here is an example that converts a floating-point number to an integer:

#include <iostream>

using namespace std;



int main()

{

	cout << "Number: " << static_cast<int>(3.14159) << "\n";



	return 0;

}

You can also assign the resulting value to a variable before using it:

#include <iostream>

using namespace std;



int main()

{

	int number = static_cast<int>(3.14159);



	cout << "Number: " << number << "\n";



	return 0;

}

The value to convert can also be the result of a calculation. The value can also be originating from an existing variable whose value you want to convert to a new type. Here is an example:

#include <iostream>

using namespace std;



int main()

{

	double PI = 3.14159;

	int number;

	

	number = static_cast<int>(PI);



	cout << "PI = " << PI << endl;

	cout << "Number = " << number << "\n";



	return 0;

}

This would produce:

PI = 3.14159

Number = 3

 

Variable Scope

 

Introduction

In the previous lesson, to declare a variable, we proceeded inside of the main() function. Such a variable could be used only inside of the square brackets of main(). In some cases, you may want to declare a variable that can be accessed from one section of the code. The section of code in which a variable can be accessed is referred to as its scope.

Local Variables

If you declare a variable inside of a function such as main(), that function can be accessed only from that function. Consider the following example:

#include <iostream>

using namespace std;



int main()

{

	double number = 3.14159;

	cout << "Number = " << number << "\n";

	

	return 0;

}

Such a variable is referred to as local because it is declared in a function. In reality, a local scope is defined by a beginning opening curly bracket "{" and a closing curly bracket "}". Everything between these brackets belongs to a local scope.

Once you have declared such a variable, you cannot declare another variable in the same scope and that bears the same name. Consider the following example:

#include <iostream>

using namespace std;



int main()

{

	double number = 3.14159;

	cout << "Number = " << number << "\n";



	double number = 2.98;

	cout << "Number = " << number << "\n";

	

	return 0;

}

This would produce a "redefinition" error and the program would not compile, even if the second declaration uses a different data type. As one type of solution to this kind of problem, C++ allows you to create a "physical" scope. To do this, you can use curly brackets to delimit the scope of a particular variable. Here is an example:

#include <iostream>

using namespace std;



int main()

{

	{

		double number = 3.14159;

		cout << "Number = " << number << "\n";

	}

	

	double number = 2.98;

	cout << "Number = " << number << "\n";



	return 0;

}

This would produce:

Number = 3.14159

Number = 2.98

In the code, notice that we delimit only the first declaration. Indeed, you can delimit each scope if you want:

#include <iostream>

using namespace std;



int main()

{

	{

		double number = 3.14159;

		cout << "Number = " << number << "\n";

	}

	

	{

		double number = 2.98;

		cout << "Number = " << number << "\n";

	}



	return 0;

}
 

Previous Copyright © 2000-2005 FunctionX, Inc.