Virtual Functions

Virtual functions provide a type of data encapsulation by giving a programmer the ability to defer object resolution until run time.

The following example is in the process of being re-written. It does illustrate the use of virtual functions, but the class model is not very pleasing.

Virtual Functions: A simple example

Here is our base class. In the real world, this class would probably inherit from all other types of classes. There would be constructors, and all other types of good things.

#include "iostream.h"

class Volkswagen {
public:
virtual int getEngineModel( ) { return 0 };
bool hasABSBrakes( );
protected:
short int engineModelNumber;
};

Our next class is derived from Volkswagen.
class Jetta : public Volkswagen {
public:
int getEngineModel( ) { return 1 };
void setCruiseControl( );
protected:
};

Our third class also inherits from Volkswagen.
class Beetle : public Volkswagen {
public:
int getEngineModel( ) { return 2 };
void setColorScheme( );
protected:
char* colorScheme;
};

Ok, our main classes are defined. The base class contains one virtual function (getEngineModel) and both derived classes also contain that function. The keyword "virtual" is optional in the function declaration for the the derived classes so I have left it out. As long as the function is defined as virtual in the base class, subsequent declarations of that class will also be virtual. Subsequent declarations of the function are said to redefine the function. That is, as long as the subsequent declaration has the same parameter signature, then by redefining it, we can overwrite its behavior. It is also possible to leave out the declaration altogether. In that case, the default definition found in the base class would be used.

A virtual function must be invoked through a public base class reference or pointer.
short int getEngineType( Volkswagen &vw ) {
          return vw.getEngineType( );
}

What value will getEngineType return when we call it? That entirely depends on what reference type we use to call it. This is what is referred to as late or run time binding. So, if I call getEngineType() with a reference to an object of type Jetta, then the function will return a short int value of one. If I call it with an reference to an object of type Beetle, then I get a 2. And of course, if I call it with a reference of type Volkswagen, I get a 0.

1