12.2.3. Casting And Member Functions

Time: 00:03:40 | Download: Large, Large (CC), Small | Streaming, Streaming (CC) | Slides (PDF)
Review

Polymorphism allows programmers to write programs that can automatically select a member function from a set of candidates. We've studied two of the requirements for polymorphism, inheritance and upcasting, in detail. Specifically, we've seen inheritance and casting effects on member variable access. Before exploring polymorphism, our only remaining task is understanding the effect of inheritance and casting on "regular" or non-polymorphic member functions. For clarity, let's remind ourselves that we are still not dealing with polymorphism but are examining how objects behave when casting is involved. The classes in our previous examples only contained member variables, but we now shift our focus to functions, and our examples reflect the shift.

UML class diagram with two classes, Parent and Child. The classes are related by inheritance: Child is a subclass of Parent. The classes only have member functions.
Parent
------------------
------------------
+function1() : void
+function2() : void

Child
------------------
------------------
+function1() : void
class Parent
{
	public:
		void function1();
		void function2();
};
class Child : public Parent
{
	public:
		void function1();
};
Member functions in an inheritance relationship. Class Child inherits both functions defined in class Parent. However, the function1 defined in class Child overrides the function1 defined in class Parent. Sometimes programmers will say that the Child function1, shadows, replaces, or hides the Parent function1. An instance of Child can still call the function1 with additional syntax.

The following code fragment demonstrates how upcasting affects function calls based on these two class specifications. Understanding which function runs in a given situation is crucial to understanding and effectively using polymorphism.

Parent*	p1 = new Parent;
Child*	p2 = new Child;
Parent*	p3 = new Child;	// upcast, Child to Parent

// Group 1
p1->function1();	// calls Parent::function1
p1->function2();	// calls Parent::function2

// Group 2
p2->function1();	// calls Child::function1
p2->function2();	// calls Parent::function2 - inherited from Parent

// Group 3
p3->function1();	// calls Parent::function1
p3->function2();	// calls Parent::function2
Selecting which function runs. Without polymorphism, the compiler searches for member functions similarly to how it searches for member variables. It searches its symbol table for a function whose name and parameter list match a function call. It begins the search based on the pointer-variable type, for example, Parent or Child. If the compiler doesn't find a matching function in the first class, it follows the inheritance link, if there is one, to the superclass.

In each example, the compiler can complete the function call binding (i.e., connecting a function call to a function's machine instructions) during the compile and link operations. Computer scientists use the terms compile time binding, early binding, and static binding to refer to this kind of function-call binding. Polymorphism changes how a program completes the function binding.

You must understand this behavior before you continue with the next section, where we take the final step and explore polymorphism.