This page was last updated August, 2004
Function Overloading and Polymorphism
Function Overloading is the ability of two functions with the same name but different parameters
and functionality to exist in the same program.
Suppose you have a situation in a program where you need fucntions to multiply
two numbers together. But, sometimes those two numbers are ints, sometimes they
are longs, sometimes floats, and sometimes doubles. You could create four
different functions:
int Multiply2Ints(int arg1, int arg2);
long Multiply2Longs(long arg1, long arg2);
float Multiply2Floats(float arg1, float arg2);
double Multiply2Doubles(double arg1, double arg2);
If, however, we use polymorphism we can define four functions with the same name
like this:
int Multiply(int arg1, int arg2);
long Multiply(long arg1, long arg2);
float Multiply(float arg1, float arg2);
double Multiply(double arg1, double arg2);
The compiler is able to determine which of these functions to call based on the type of arguments.
It is even able to call the correct function when the number of arguments is different as in the following
int Multiply (int arg1, int arg2, int arg3);
long Multiply (long arg1, long arg2, long arg3);
float Multiply (float arg1, float arg2, float arg3);
double Multiply (double arg1, double arg2, double arg3);
In fact all the arguments do not even have to be the same type as in the following:
long Multiply (int arg1, long arg2);
double Multiply (float arg1, double arg2);
Below is an example of a short program demonstrating this:
//=======================================================
// File: main.cpp
// Purpose: Demonstrate function overloading
// Author: Dr. Rick Coleman
//=======================================================
#include <iostream.h>
// Function prototypes
int Multiply (int arg1, int arg2);
long Multiply (long arg1, long arg2);
float Multiply (float arg1, float arg2);
double Multiply (double arg1, double arg2);
int Multiply (int arg1, int arg2, int arg3);
long Multiply (long arg1, long arg2, long arg3);
float Multiply (float arg1, float arg2, float arg3);
double Multiply (double arg1, double arg2, double arg3);
long Multiply (int arg1, long arg2);
double Multiply (float arg1, double arg2);
int main()
{
int a = 1, b = 2, c = 3;
long d = 4, e = 5, f = 6;
float g = 7.0f, h = 8.0f, i = 9.0f;
double j = 10.0, k = 11.0, l = 12.0;
cout << "Multiply(int, int) = " << Multiply(a, b) << "\n";
cout << "Multiply(long, long) = " << Multiply(d, e) << "\n";
cout << "Multiply(float, float) = " << Multiply(g, h) << "\n";
cout << "Multiply(double, double) = " << Multiply(j, k) << "\n";
cout << "Multiply(int, int, int) = " << Multiply(a, b, c) << "\n";
cout << "Multiply(long, long, long) = " << Multiply(d, e, f) << "\n";
cout << "Multiply(float, float, float) = " << Multiply(g, h, i) << "\n";
cout << "Multiply(double, double, double) = " << Multiply(j, k, l) << "\n";
cout << "Multiply(int, long) = " << Multiply(a, d) << "\n";
cout << "Multiply(float, double) = " << Multiply(g, j) << "\n";
return 0;
}
// Multiply two ints
int Multiply (int arg1, int arg2)
{
return arg1 * arg2;
}
// Multiply two longs
long Multiply (long arg1, long arg2)
{
return arg1 * arg2;
}
// Multiply two floats
float Multiply (float arg1, float arg2)
{
return arg1 * arg2;
}
// Multiply two doubles
double Multiply (double arg1, double arg2)
{
return arg1 * arg2;
}
// Multiply three ints
int Multiply (int arg1, int arg2, int arg3)
{
return arg1 * arg2 * arg3;
}
// Multiply three longs
long Multiply (long arg1, long arg2, long arg3)
{
return arg1 * arg2 * arg3;
}
// Multiply three floats
float Multiply (float arg1, float arg2, float arg3)
{
return arg1 * arg2 * arg3;
}
// Multiply three doubles
double Multiply (double arg1, double arg2, double arg3)
{
return arg1 * arg2 * arg3;
}
// Multiply an int and a long
long Multiply (int arg1, long arg2)
{
return arg1 * arg2;
}
// Multiply a float and a double
double Multiply (float arg1, double arg2)
{
return arg1 * arg2;
}
Polymorphism is the ability of different sub-classes of a parent class to inherit
functions from the parent class yet implement the functions in very different ways. In a way this
is function overloading by changing the function’s operation.
A classical example of this is in a drawing application. Suppose you
wanted to create a drawing package in which the user could select from
a tool bar a rectangle, oval, etc. shape and then draw that shape using
mouse click-and-drag operations. This could be implemented by creating
a rectangle class, an oval class, and a class for each of the shapes
you want to draw. Since all these shapes would share many common characteristics,
such as line color, fill color, line pattern, fill pattern, a bounding
rectangle, etc. it makes sense to create a shape class and then create
sub-classes of this class. Below is the header file for an application
which defines a CShape class. Note: If this were an actual program we
would have all the common variables like line color defined in this
file and let them be inherited by the sub-classes.
//============================================================
// File: CShape.h
// Purpose: Define the base class for a shape hierarchy
// Author: Dr. Rick Coleman
//============================================================
#ifndef CSHAPE_H
#define CSHAPE_H
class CShape
{
public:
CShape();
~CShape();
virtual void draw();
};
#endif
Notice how the draw() function is defined in CShape.h. It is
declared as virtual. This means that all subclasses
will be required to implement this function instead of inheriting
it from the parent class. We can now proceed to define a CRectangle
class and a COval class as shown below.
//============================================================
// File: CRect.h
// Purpose: Define the derived rectangle class
// Author: Dr. Rick Coleman
//============================================================
#ifndef CRECT_H
#define CRECT_H
#include "CShape.h"
class CRect:CShape
{
public:
CRect();
~CRect();
void draw();
};
#endif
//============================================================
// File: COval.h
// Purpose: Define the derived oval class
// Author: Dr. Rick Coleman
//============================================================
#ifndef COVAL_H
#define COVAL_H
#include "CShape.h"
class COval:CShape
{
public:
COval();
~COval();
void draw();
};
#endif
Note that in CRect.h and COval.h the draw function is not declared
as virtual. In each case the code in the class would be written to
draw the appropriate shape.
With these classes we could now create some simple program using the
classes such as the one below.
//============================================================
// File: ShapeDemo.cpp
// Purpose: Demonstrate the use of polymorphism.
// Author: Dr. Rick Coleman
//============================================================
#include "CShape.h"
#include "CRect.h"
#include "COval.h"
int main(void)
{
CShape *theRect, *theOval; // Declare pointers to two CShape objects
theRect = new(CRect); // Instantiate this CShape as a CRect object
theOval = new(COval); // Instantiate this CShape as a COval object
// Call appropriate functions to set drawing colors, sizes etc. for each
// Call the functions in the each sub-class to tell the objects to draw themselves
theRect->Draw();
theOval->Draw();
// Do some other stuff here
// Destroy the objects when finished
delete theRect;
delete theOval;
}