Objectives: The C++ Programming Skills That Should Be Acquired in This Lab
Objectives: The C++ Programming Skills That Should Be Acquired in This Lab
Polymorphism
Objectives
Example 9.1
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << rect.area() << endl;
cout << trgl.area() << endl;
return 0;
}
Output:
20
10
In function main, we create two pointers that point to objects of class CPolygon (ppoly1
and ppoly2). Then we assign references to rect and trgl to these pointers, and because
both are objects of classes derived from CPolygon, both are valid assignment
operations.
The only limitation in using *ppoly1 and *ppoly2 instead of rect and trgl is that both
*ppoly1 and *ppoly2 are of type CPolygon* and therefore we can only use these
pointers to refer to the members that CRectangle and CTriangle inherit from CPolygon.
For that reason when we call the area() members at the end of the program we have
had to use directly the objects rect and trgl instead of the pointers *ppoly1 and *ppoly2.
In order to use area() with the pointers to class CPolygon, this member should also
have been declared in the class CPolygon, and not only in its derived classes, but the
problem is that CRectangle and CTriangle implement different versions of area,
therefore we cannot implement it in the base class (If we do, the base class version is
called). This is when virtual members become handy.
Virtual Members
A member of a class that can be redefined in its derived classes is known as a virtual
member. In order to declare a member of a class as virtual, we must precede its
declaration with the keyword virtual.
Example 9.2
// virtual members
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area ()
{ return (0); }
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon poly;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
CPolygon * ppoly3 = &poly;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly3->set_values (4,5);
cout << ppoly1->area() << endl;
cout << ppoly2->area() << endl;
cout << ppoly3->area() << endl;
return 0;
}
Output
20
10
0
Now the three classes (CPolygon, CRectangle and CTriangle) have all the same
members: width, height, set_values() and area().
The member function area() has been declared as virtual in the base class because it is
later redefined in each derived class. You can verify if you want that if you remove this
virtual keyword from the declaration of area() within CPolygon, and then you run the
program the result will be 0 for the three polygons instead of 20, 10 and 0. That is
because instead of calling the corresponding area() function for each object
(CRectangle::area(), CTriangle::area() and CPolygon::area(), respectively),
CPolygon::area() will be called in all cases since the calls are via a pointer whose type
is CPolygon*.
Therefore, what the virtual keyword does is to allow a member of a derived class with
the same name as one in the base class to be appropriately called from a pointer, and
more precisely when the type of the pointer is a pointer to the base class but is pointing
to an object of the derived class, as in the above example.
Note that despite of its virtuality, we have also been able to declare an object of type
CPolygon and to call its own area() function, which always returns 0.
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a;
height=b; }
The main difference between an abstract base class and a regular polymorphic class is
that because in abstract base classes at least one of its members lacks implementation
we cannot create instances (objects) of it.
But a class that cannot instantiate objects is not totally useless. We can create pointers
to it and take advantage of all its polymorphic abilities. Therefore a declaration like:
CPolygon poly;
would not be valid for the abstract base class we have just declared, because tries to
instantiate an object. Nevertheless, the following pointers:
CPolygon * ppoly1;
CPolygon * ppoly2;
This is so for as long as CPolygon includes a pure virtual function and therefore it's an
abstract base class. However, pointers to this abstract base class can be used to point
to objects of derived classes.
Example 9.4
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() << endl;
cout << ppoly2->area() << endl;
return 0;
}
Output
20
10
Example 9.5
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() << endl; }
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
return 0;
}
Output
20
10
Virtual members and abstract classes grant C++ the polymorphic characteristics that
make object-oriented programming such a useful instrument in big projects.
Example 9.6
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() << endl; }
};
Output:
20
10