http://www.developer.com/

Back to article

Understanding OO Essentials: Classes, Inheritance, Polymorphism and Interfaces


December 31, 2002

When you first begin to wade into the deep end of an object oriented language you find yourself inundated with esoteric concepts and strange terminology. You may half-understand conversations and read books and articles that all seem to assume a basic set of knowledge that you don't fully grasp. It can be a frustrating experience! After all you are no green-horn. You've done your share of development. So why is all this so confusing?

The fact is that it doesn't have to be. Because object-oriented development originated in the academic world, it comes with a whole new vocabulary and a whole lot of complicated descriptions for pretty simple ideas.

In this article, my goal is to give you the knowledge that all those books and magazines assume you already know. You won't learn all there is to know about object-oriented development. But you will get enough of the concepts and terminology down to give you a solid foundation to build on.

Objects, properties and methods

It would be difficult to be a programmer today, no matter what programming language you use, and avoid working with objects in one way or another. Objects are simply containers for variables and functions that logically go together. In object-oriented parlance, variables and functions inside an object are called properties and methods. In most languages, you use dot-notation to refer to an object's properties and methods. For example, if you have an object named Customer and you wanted to assign a value to its Name property, you would use syntax that looks something like this:

Customer.Name = "Fred Smith"

Or if you wanted to call a Customer method called PrintInvoice(), it might look something like this:

Customer.PrintInvoice()

When used like this, objects are simply a way of organizing data and code into logical collections. But there's more to object-oriented programming than that!

Classes and instantiation

The terms class and object are sometimes used interchangeably. This makes understanding the difference between the two that much more difficult. They are distinct, but related.

Think of a class as a detailed description of an object. A class is not an object, but it contains all the information needed to create an object. It's like the relationship between a blueprint and a house. Here's an example of a class definition in Visual Basic .NET. (Although the syntax will be slightly different in different languages, the structure is usually roughly the same.)

Class EmpClass   Public Name As String   Public Phone As String   Public Hours As Integer   Public Rate As Single   Public Function CalcPay()      Return Hours * Rate   End FunctionEnd Class

A class definition is simply a group of variable and function declarations grouped together and given a name.

Although the blueprint contains all the details necessary to create a house, you can't live in a blueprint. Before you can have someplace to live, a process must take place: building. In order for you to make use of a class, a process must take place: instantiation.

Instantiation (literally meaning "to make an instance of") is how objects are created from a class. Once an object is created, you can assign values to its properties and call its methods. Every language has its own syntax for instantiating objects from classes. However most of them use the keyword New in one way or another. Here's an example of instantiation syntax in Visual Basic .NET.

Dim EmpObj As EmpClassEmpObj = New EmpClass

First a variable is declared. The class name here, CustClass, is used just like a data type would be in any variable declaration. But this does not instantiate the object. It simply declares a variable that will point to the object, once it is created.

The next line is where the instantiation takes place. The New keyword is followed by the name of the class to instantiate. Again, although the syntax in the language of your preference will likely be a little different, the two-step process of creating a reference variable and then instantiating the object and assigning it to the reference variable will likely be the same. (Although some languages provide a shortcut syntax to do both in one line.)

Once the object is allocated in memory, CustObj becomes a reference to that object and can be used as you would any object.

EmpObj.Hours = 40EmpObj.Rate = 6.50Total = EmpObj.CalPay()

At this point you might be thinking, "Wait a minute — I've written code before that uses objects, but I didn't have to write any instantiation code. How is that possible?" See the sidebar titled "Automatically Instantiated Objects, Static Classes and Other Black Magic".

But what's the point of this extra level of complexity? Why must you describe a class and instantiate the class as an object before you can use it? Why not just describe the object and be finished with it? Well, there's one very good reason: Many objects can be instantiated from a single class. When you do this, each object will contain the same set of properties and methods. However, each object is independent and its properties can have different values.

Here's an example where two employee objects are created from the same employee class and each are assigned different values.

Dim Emp1Obj As EmpClassDim Emp2Obj As EmpClassEmp1Obj = New EmpClassEmp2Obj = New EmpClassEmp1Obj.Name = "Fred Smith"Emp2Obj.Name = "Bob Jones"

Automatically Instantiated Objects, Static Classes and Other Black Magic

I stated pretty clearly that you can't use a class until you've instantiated it, any more than you can live in a blueprint. And that's the general rule. Now for the exceptions

Many languages and development environments automatically instantiate objects for you behind the scenes. Typically these are objects that often need to be accessed but ones which you'll never need more than one instance. So technically this isn't an exception to the rule. But it does look like one when you are working in such environments because you are not responsible for the instantiation and may not even be able to see the code where it's actually done.

There is another case that really is an exception to the rule, however. Some classes are designed to be used directly. These are called static classes. Often static classes are collections of utility functions associated with a particular task, like file manipulation. Making such classes static just saves you a couple of step when you go to use them.

Inheritance

So far, classes and objects seem like little more than just a fancy way to bundle code together, like an advanced include module, for example. But there is one important ingredient to object oriented programming that completely sets it apart: inheritance.

Inheritance is the ability to start with an existing class and use it as a starting point for creating another class. So what? You can copy and paste code from a module and do the same thing, right? But suppose you've used a base module as the starting point for several others. Then you make a change to that base module. In order for that change to be reflected in all those other modules, you have to go and make the change there, too. This is actually a very common scenario and a major cause for inconsistencies and bugs in all kinds of applications.

Inheritance is different. When you inherit from a class, the new class (often called the child class) maintains a connection with the original class (often called the parent). This connection assures that any change in the parent is automatically also made in all its children as well.

And inheritance works for multiple generations as well. That is, you can inherit from a parent to create a child. Then you can inherit from the child to create a grandchild. Any changes made to either the parent or child is reflected in the grandchild.

As you might imagine, this means that you have the ability to create intricate and complex structures or inheritance hierarchies. Inheritance is a powerful feature. But its the kind of power that's easy to abuse and significantly more difficult to use well.

What's the best strategy for creating an inheritance hierarchy? The first rule is to think in terms of generalization. The higher the class is in the hierarchy, the more general and abstract it should be. The lower you get in the class hierarchy, the more concrete and specific the classes should be.

Here's an example. Suppose you decide to reengineer your EmpClass to take advantage of inheritance. Your highest-level class might be Employee. It would contain properties like Name and Phone. Inherited from Employee might be a class called SalariedEmployee. Properties of this class would include the Name and Phone that was inherited from Employee, but it would also include a property called Salary. At the same time you might have another class that inherits from Employee called HourlyEmployee. In addition to the items that were inherited from the Employee class, this class may contain properties like Hours and Rate.

Here's what it would look like in Visual Basic .NET.

Class Employee   Public Name As String   Public Phone As StringEnd ClassClass SalariedEmployee   Inherits Employee   Public Salary As LongEnd ClassClass HourlyEmployee   Inherits Employee   Public Hours As Integer   Public Rate As SingleEnd Class

Once you've created this hierarchy, you can use the child classes as if the parent properties were directly apart of them.

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.50

Polymorphism

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.

Interfaces

I think the best way to demonstrate what an interface is and how it can work for you is to start off with an example. Suppose the company you work for is progressively minded (I hope that's not too big of a stretch for you!) and that they'd like for all their employees receive at least 10 days of training a year. They want to add the ability to track this to their systems, but in addition to tracking training for both salaried and hourly employees, they also want to track training of contractors.

Both SalariedEmployee and HourlyEmployee are children of Employee, but Contractor is not. And there's no easy way to reengineer the system so that it could be. So, unfortunately, polymorphism isn't an option here. What other options are there?

When you have a situation where you have common functionality across a number of very different classes and there's no close, common parent object that would make polymorphism work, the best option is usually an interface. This can happen often when you don't have multiple inheritance, because you are always limited to one and only one parent for your class.

Here's what an interface definition might look like for the training tracking system.

Interface TrainingTracking   Sub AddTrainingDays(ByVal Num As Integer)   Function GetTriainingDaysTotal() As IntegerEnd Interface

An interface is a description of some of the members available from a class. In practice, the syntax typically looks similar to a class definition, except that there's no code defined for the methods — just their name, the arguments passed and the type of the value returned.

So what good is it? None by itself. But you create an interface so that classes will implement it. Here's the Contractor class.

Class ContractorImplements TrainingTrackingPrivate TrainingDays As IntegerPublic Name As StringPublic Phone As StringPublic Sub AddTrainingDays(ByVal Num As Integer) _   Implements TrainingTracking.AddTrainingDays   TrainingDays = TrainingDays + NumEnd SubPublic Function GetTriainingDaysTotal() As Integer _   Implements TrainingTracking.GetTriainingDaysTotal   Return TrainingDaysEnd FunctionEnd Class

In this example, Contractor does not have an Inherits clause and does not inherit from anything. But in the real world, it probably would, which would prevent it from inheriting from Employee.

However you'll notice that it does have another clause that looks similar: Implements. Implements is always followed by the names of one or more interfaces. Notice that although a class can only have one class that it inherits from, it can have any number of interfaces that it implements.

But what does it mean to implement an interface. The interface acts as a contract or promise. If a class implements an interface, then it must have the properties and methods of the interface defined in the class. This is enforced by the compiler.

Of course the person writing the class can choose to implement the methods however he wants, but the name, arguments and return type of each method must be identical to the definition in the interface.

In this case, the two methods, one to add days to the training for the contractor and one to retrieve the total are both implemented as they should be. In addition, in Visual Basic .NET, it is necessary to indicate to the compiler which interface method this method is designed to implement by using the Implements keyword again in the subroutine/function definition. The same is true for the other Employee classes of this system.

Class SalariedEmployeeInherits EmployeeImplements TrainingTrackingPrivate TrainingDays As Integer...Public Sub AddTrainingDays(ByVal Num As Integer) _   Implements TrainingTracking.AddTrainingDays   TrainingDays = TrainingDays + NumEnd SubPublic Function GetTriainingDaysTotal() As Integer _   Implements TrainingTracking.GetTriainingDaysTotal    Return TrainingDaysEnd FunctionEnd ClassClass HourlyEmployeeInherits EmployeeImplements TrainingTracking...Public Sub AddTrainingDays(ByVal Num As Integer) _   Implements TrainingTracking.AddTrainingDays   TrainingDays = TrainingDays + NumEnd SubPublic Function GetTriainingDaysTotal() As Integer _   Implements TrainingTracking.GetTriainingDaysTotal   Return TrainingDaysEnd FunctionEnd Class

So you can use interfaces as a way to standardize certain common functionality across many classes. By doing this you assure that classes that have similar functionality implement it in the same way. Of course, the interface doesn't make any guarantees about how a given class will implement the methods of the interface, but it does give you a clear idea of what methods are available and how to call them.

But the best part of interfaces is putting them to use. It works just like polymorphism! Suppose for example, that when employees or contractors joined the company, they were put through a three-day new employee seminar. These three days count toward their training, so you create a new subroutine that can easily be called whenever a new employee has completed the seminar.

Sub TrackNewEmployeeSeminar(ByVal Person As TrainingTracking)   Person.AddTrainingDays(3)End Sub

The thing to notice here is that the argument passed in to the subroutine is of type TrainingTracking, the name of the interface. But you can't instantiate an interface! What does this mean? As you might suspect, this means that an object is being passed that implements the TrainingTracking interface. When you use this object, you can't make any more assumptions about it than that. But you can be sure that the members defined in the interface are available.

So, in this case, the AddTrainingDays method is called with an argument indicating the training lasted three days.

Here's code which calls this subroutine.

TrackNewEmployeeSeminar(Emp1)TrackNewEmployeeSeminar(Emp2)MsgBox("Emp1 Training:" & Emp1.GetTriainingDaysTotal)MsgBox("Emp2 Training:" & Emp2.GetTriainingDaysTotal)

It doesn't matter if the object passed is a SalariedEmployee, an HourlyEmployee or a Contractor. We know it will have the AddTrainingDays because we know it implements the TrainingTracking interface. If you try to send an object that doesn't implement that interface, you'll receive an error.

About the Author

Bill Hatfield is a trainer, consultant, and the author of ASP.NET for Dummies, among other books.

# # #

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date