If we use the print() function in the context of a Contractor we find the Contractor version, but the Employee function can be accessed...
ct1.Employee::print();
What if the signatures were different? Say we had the following in Employee ...
void print(int) const;
A call for print(int) ...
ct1.print(2);
... won’t work, it’s out of scope, so hidden. If there wasn’t a print in the derived class the base class would be checked, and then the base of that...
That’s one type of hiding, a subclass function with a different parameter list. Another type is to do with variable name re-use in a member function.
So if we modified the print function as follows ...
void Contractor ::print(int hours) const
{
this->hours, (*this).hours // to access class hours.
}
References to hours in that function would default to the local hours.
There would likely be a compiler warning about the variable being hidden.
When any class member function is called, the following steps take place:
The compiler looks for a matching function in the class of the object using the function name.
If no match is found in this class, the compiler looks for a matching function in the parent class.
If no match is found in the parent class, the compiler continues up the inheritance hierarchy, looking at the parent of the parent, until the base class is reached.
If no match is found in any class, this results in a compilation error.
If a base class contains a public function that does not apply to the derived class, you can create a dummy function with the same name in the derived class.
According to the rules it will be found first and we go no further.
If you leave the derived class version public, it can be called but will do nothing. If you make it private, then it can’t be called outside the class itself, the compiler will complain if anyone tries to call that function using a class, or descendant, object.
int main()
{
Contractor cn( "Bob", "Smith", 40.0, 10.00 );
// use derived class reference
Contractor& r1 = cn;
r1.print(); // use base class reference
Employee& r2 = cn;
r2.print(); // Use derived class pointer
Contractor *p1 = &cn;
p1->print(); // Which print() ?
// use base class pointer
Employee *p2 = &cn;
p2->print();
// casting base-class pointer to derived-class pointer
p1 = static_cast<Contractor*>(p2);
p1->print();
return 0;
}
This is storing the content of an object as if it were of a different type.
Typically used to let a compiler know that we are okay downgrading the precision, for example float to int.
Statically casting a base-class pointer to a derived–class pointer is a bad idea, don’t do it. Trying to turn a base-class object into a derived-class object is likely to cause runtime errors. In this case it worked, because although p2 was a base-class pointer, the object it was pointing to was really of the derived class.
But we don’t want to have to keep track of the real type of every object in an array of base-class pointers in order to use them properly!
The compiler time binding in the previous example has limitations.