Classes that have at least one virtual function are referred to as being of polymorphic type. Making the base class function virtual means it’s virtual in the derived classes too, even if we don’t specify it as such.
It’s good practice to make it explicit at every level to help keep track of what’s going on.
Provided the derived class functions have the same name, signature, and return type as the virtual function in the base class, the derived function is said to override the base class function and we will have dynamic binding.
Polymorphism is about being able to access different objects through the same interface. We can use a base class function modified for the specific subclasses to determine the appropriate behaviour for the action (method) on an object.
Overloading can be thought of a different form of polymorphism, we still have many forms of something, but the term polymorphism by itself is most likely to refer to the polymorphic types related through an inheritance hierarchy.
When we use inheritance the derived classes sometimes ...
... retain base behaviours.
... add new behaviours.
... modify base behaviours.
The most interesting of these is the third one, modifying base behaviours. Let’s look at an example to see why.
class Employee {
public:
Employee( const char *, const char * );
void print() const;
~Employee();
private:
char *firstName;
char *lastName;
};
Employee :: Employee( const char *first, const char *last )
{
firstName = new char[ strlen( first ) + 1 ];
strcpy( firstName, first );
lastName = new char[ strlen( last ) + 1 ];
strcpy( lastName, last );
}
void Employee :: print() const
{
cout << "Employee::print() is executing" << endl;
cout << firstName << " " << lastName;
}
Employee :: ~Employee()
{
delete [] firstName;
delete [] lastName;
}
class Contractor : public Employee {
public:
Contractor( const char*, const char*, float, float );
float getPay() const;
void print() const;
// Employee had one too!
private:
float rate;
float hours;
};
Every Contractor is an Employee, so inherits the data members the Employee has - firstName, lastName.
However, we can only access those through the Employee public member functions.
A member function in a derived class with the same name as in the base class hides the function of the base class.
This happens with print().
Contractor::Contractor(const char *first, const char *last, float inHours, float inRate)
: Employee( first, last )
{
hours = inHours;
rate = inRate;
}
float Contractor::getPay() const
{
return rate * hours;
}
void Contractor::print() const
{
cout << "Contractor::print() is executing" <<endl;
Employee::print();
cout << " is a contractor with pay of $" << setiosflags( ios::fixed | ios::showpoint) << setprecision( 2 ) << getPay() << endl;
}
Contractor::print() uses Employee::print().
Need #include <iomanip> for the setios things ...
Finally, running the main function, ...
int main()
{
Contractor ct1( "Bob", "Smith", 40.0, 10.00 );
ct1.print();
return 0;
}
... Ouput ...
Contractor::print() is executing
Employee::print() is executing
Bob Smith is a contractor with pay of $400.0