
Class constructors, when executed, allocate in memory an object of a defined type. This object can inherit properties from a base class, and if this is the case, class constructors use virtual function pointers to point to the class's virtual function table (v-table). That is a table that points to the members of the interfaces that an object supports and enables proper binding of virtual functions.
If a constructor is overloaded, this constructor can become polymorphic; in other words, it will perform different operations depending on the type of arguments it receives when it is bound at run time.
For example, you could have a generic class constructor Person(){} and an overloaded class constructor Person(string personName, float personAge){}. The first constructor could initialize the object in memory with default values, but the object that is instantiated with the constructor that receives as an argument age will initialize an object with a defined age. If our class person inherits properties from a base class LivingThing(){}, in this case we will have polymorphic class constructors that are derived from a base class LivingThing(){}.

The output would have been this:

The constructor bound the proper method according to the arguments received, or when the object is instantiated. Polymorphism is achieved through late binding or dynamic binding. Dynamic binding is when at run time it is determined which function to call for a particular object or determining what type of method will be used until a program is on its execution phase. Polymorphism allows programmers a great deal of flexibility and power.
The opposite of dynamic binding is static binding; that is when at compile time it is determined which functions will call a particular object. This approach of static binding does not allow exploiting the full potential of object-oriented programming.
You might be wondering when to use virtual functions, and whether this causes a lot of security and control problems. Remember that a derived class inherits the members of its base class but only those that are declared public or protected. If you need an extra control, you could use static methods and attributes to control the number of objects derived from a given class.
Base classes have the common code implemented on them, and the specific code is implemented on the derived classes. It is recommended that the base class establish a protocol through which the derived classes can attain maximum capability. Using virtual functions allows you to do this, and if you are not convinced with the methods on the base class, you can always override a method.
You can use the following code and compile it to test the properties of virtual functions. The general description of the classes is:
Base Class: Human
Derived Classes: sportsPro and Trainer
Human Class Description

SportsPro Class Description

Trainer Class Description

#include <ctype.h>
#include <string.h>
#include <iostream.h>
class Human
{
private:
char
name[100];
protected:
float
numberTrainingHours;
float
HomePay;
public:
Human(char*
myname, float
mynumberTrainingHours);
const
char*
getName()
{
return
name;
};
{
virtual
void
calcHomePay() = 0;
virtual
void
print() = 0;
};
class sportsPro :
public Human
{
private:
static
int
payPerPub;
static
float
payPerPubPromoted;
char
Promoted;
protected:
int
Tournaments;
public:
sportsPro(char*
myname, float
mynumberTrainingHours,
char amIPromoted,
int pubs);
void
calcHomePay();
void
print();
};
class Trainer :
public Human
{
private:
static
int
payPerSem;
protected:
int
semExperience;
public:
Trainer(char*
myname, float
mynumberTrainingHours,
int sems);
void
calcHomePay();
void
print();
};
Human::Human(char
*myname, float
mynumberTrainingHours)
{
strcpy(this->name, myname);
this->numberTrainingHours = mynumberTrainingHours;
};
Trainer::Trainer(char
*myname, float
mynumberTrainingHours,
int sems):Human(myname, mynumberTrainingHours)
{
this->semExperience = sems;
};
void Human::print()
{
cout<< "Home Pay: " <<
this->numberTrainingHours <<
endl;
}
void Trainer::calcHomePay()
{
float
toTrainerlPay;
toTrainerlPay = this->numberTrainingHours
+ ((this->semExperience)*50);
this->numberTrainingHours = toTrainerlPay;
}
void sportsPro::calcHomePay()
{
float
toTrainerlPay;
if(this->Promoted == 'Y')
{
toTrainerlPay = this->numberTrainingHours
+ ((this->Tournaments)*200);
}
else
toTrainerlPay = this->numberTrainingHours
+ ((this->Tournaments)*100);
this->numberTrainingHours
= toTrainerlPay;
}
void sportsPro::print()
{ const
char
*tmp;
tmp = Human::getName();
char
nameX[100];
for(int
fill = 0; fill< 100; fill++)
{
nameX[fill] = '@';
}
strcpy(nameX, tmp);
cout<< "Professional Name: ";
for(int
i = 0; i < 100; i++)
{
if(nameX[i] != '@')
{
cout << nameX[i];
}
}
if(this->Promoted=='Y')
cout<< "" <<endl;
else
cout << "without promotion"<<endl;
cout << ": " <<this->Tournaments<<endl;
Human::print();
}
void Trainer::print()
{
const
char
*tmp;
tmp = Human::getName();
char
nameX[100];
for(int
fill = 0; fill< 100; fill++)
{
nameX[fill] = '@';
}
strcpy(nameX, tmp);
cout<< "Name: ";
for(int
i = 0; i < 100; i++)
{
if(nameX[i] != '@')
{
cout << nameX[i];
}
}
cout <<endl;
Human::print();
}
sportsPro::sportsPro(char
*myname, float
mynumberTrainingHours,
char amIPromoted,
int pubs) : Human(myname,
mynumberTrainingHours)
{
this->Tournaments = pubs;
this->Promoted= amIPromoted;
};
#define MAXPEOPLE 4
int main()
{
cout << "************ Virtual Functions**************";
cout << "Gustavo R. Pares";
cout << "gusabc_mx@yahoo.com.mx";
cout << "http://mx.geocities.com/gusabc_mx ";
cout << "********************************************";
Human* arr[MAXPEOPLE];
int
i;
arr[0] = new
sportsPro("Andre A.", 4112.50, 'N', 3);
arr[1] = new
sportsPro("Joe M.", 4112.50, 'Y', 10);
arr[2] = new
Trainer("Mr. Wilson ", 1000.50, 1);
arr[3] = new
Trainer("Mr. Adidas", 1000.50, 6);
for(i=0 ; i< MAXPEOPLE ; ++i)
{
arr[i]->calcHomePay();
arr[i]->print();
cout<<endl;
}
for(i=0 ; i<MAXPEOPLE ; ++i)
delete
arr[i];
int
out = 1;
cout<< "- To exit type (4) >> ";
do{
cin >> out;
}while(out < 2);
return
0;
}
Bibliography