Understanding OO Essentials: Classes, Inheritance, Polymorphism and Interfaces, Page 3
Polymorphism is a perfect example of a scary, confusing term used to describe a simple concept. Simple — but very powerful!
You may have noticed that I dropped the CalcPay method from the reengineered example. How would you do CalcPay now? Well, CalcPay should be in both the SalariedEmployee class and in the HourlyEmployee class. So you might suspect that it should be placed in the Employee class. Normally that would be right, but this time, there's one catch: Although each class should have a CalcPay method, the implementation of that method will be different for each class. For the HourlyEmployee, you want to multiply the Hours by the Rate as you did before. But for the SalariedEmployee, you probably want to divide the salary by 52, since the number there is for the year. So how do you do it?
This is exactly the kind of problem Polymorphism was created to solve. It allows you to have the same method in two different child classes, each with a different implementation.
The first step is to put an empty CalcPay method in the parent class. As I mentioned, the definition for the method should be there since it's going to be shared among the children. However, since the children are going to have different implementations of the method, no implementation appears in the parent class. In addition, the method is identified as Overridable. Different languages have different syntaxes for identifying a function this way, but they all mean the same thing &mash; that classes inherited from this class are welcome to create their own implementation of this method
Class Employee Public Name As String Public Phone As String Public Overridable Function CalcPay() End FunctionEnd Class
Now all that's left is to actually implement the method as you like in each of the child classes. Note that the keyword Overrides is used here in Visual Basic .NET. Again, other languages may use different syntax, but the goal is to make it clear that this method is overriding whatever definition was in the parent for this method.
Class SalariedEmployee Inherits Employee Public Salary As Long Public Overrides Function CalcPay() Return Salary / 52 End FunctionEnd ClassClass HourlyEmployee Inherits Employee Public Hours As Integer Public Rate As Single Public Overrides Function CalcPay() Return Hours * Rate End FunctionEnd Class
Not too complicated, right? But once you've set up this kind of structure, the magic comes in how you can handle these classes.
Suppose now that you want to create a subroutine that receives an employee — any type of employee and displays their pay for this week. Essentially you want to be able to do this:
Dim Emp1 As SalariedEmployeeDim Emp2 As HourlyEmployeeEmp1 = New SalariedEmployeeEmp2 = New HourlyEmployeeEmp1.Name = "Fred Smith"Emp1.Phone = "555-1331"Emp1.Salary = 26000Emp2.Name = "Bob Jones"Emp2.Phone = "555-1331"Emp2.Hours = 40Emp2.Rate = 6.5ShowPay(Emp1)ShowPay(Emp2)
Note that Emp1 is actually a SalariedEmployee and Emp2 is actually an HourlyEmployee — but you call the same subroutine for displaying both. How would you write a subroutine that can handle this? It's actually pretty simple.
Sub ShowPay(ByVal Emp As Employee) MsgBox(Emp.CalcPay())End Sub
It receives an employee and calls the CalcPay method for that employee. Notice that it doesn't receive either a SalariedEmployee or an HourlyEmployee. Instead the argument has the type of the parent class. When the subroutine receives an object as an argument, the object passed can actually be an object of the class specified (in this case Employee) or any child of that class (like SalariedEmployee or HourlyEmployee).
Since CalcPay is a valid function in the Employee class (though it's empty), the compiler won't throw an error when you call CalcPay for an Employee-type object.
More importantly, when you call the CalcPay method, the appropriate child method is the one that's actually called. That is, when the ShowPay subroutine calls the CalcPay method when Emp1 is passed, the computer will figure out at runtime that the object passed is actually a SalariedEmployee-type object and call the CalcPay of SalariedEmployee. Likewise, when Emp2 is passed, the computer figures out that the object is actually an HourlyEmployee and calls that CalcPay method.
This is polymorphism — the ability to refer to an object using a parent class and yet be able to call the appropriate child method. This flexibility allows you to write generic code that can work not just on one class of objects but on a whole set of classes, as the ShowPay subroutine does here.
The Problem of a Plurality of Parents
Polymorphism is a very cool capability and is useful in a big variety of situations. But there is a catch: All the objects that are used in polymorphism have to be children (or grandchildren, great-grandchildren, etc.) of a common parent. And the functionality that you want to use has to be defined at the parent's level (like the blank CalcPay function was in Employee). Then the children can override the function in any way they like.
But suppose you want to use some of the functionality that's in one parent and some of the functionality that's in another parent? Is it possible to inherit from more than one parent?
It depends on the language you are programming in. In C++, it is possible to inherit from multiple parents (a feature called multiple inheritance). When you do, all the properties and methods from all the parent classes become a part of your class. This sounds like a very nice, flexible solution. And it is. However, in practice, this can get very confusing very quickly. Suppose you create a class that inherits from two completely different classes, and both have a method named CalculateExpenses. Which one takes precedence? What if you want to use both of them at different times for different things?
Inheritance hierarchies can be complex on their own. Adding the possibility of multiple inheritance makes the complexity very difficult to manage and often becomes the source of difficult-to-find bugs in code.
Because of these difficulties, more modern object oriented languages like Java, C# and Visual Basic .NET have dropped multiple inheritance and limit your classes to inheriting from one and only one parent.
But this still leaves you with the problem that started the whole discussion: What if your class needs to borrow some functionality from one class and other functionality from a completely different class?
In recent years, one solution has come to the fore in many different programming environments to address this need: interfaces.