The second pillar of OOP is Inheritance. But if you read the title of today’s blog, you probably already guessed that. Inheritance allows us to both reuse and extend code, plus allow you to easily make changes to a class and have them ripple through to the decedents.
Take a look at the Employee class from yesterday. When I think of employees in a company, I can think of at least two kinds, Managers and Peons (like me). Both are types of employees, but both have some things different. Inheritance allows us to reuse the best parts of employees, but add special functionality as well.
Let’s create a new class, called Manager. Here’s what I coded:
using System;
using System.Collections.Generic;
using System.Text;
namespace OOPDemo
{
class Manager : Employee
{
// Constructor, call the base
public Manager(): base()
{
}
// Meaningless work, just like a real manager would do.
public void MakeHairPointy()
{
string myPointyHairOrder = “Write me a program by last week.”;
}
}
}
The first thing you may notice is the : Employee after the class Manager. This tells the compiler that the Manager class is descended from the Employee class. Any methods, properties, and events available in the Employee class are now automatically available in the Manager class.
Next you see a line that says public Manager(). This is the constructor for the class. In here you can put code that you want to execute when the class is created. Perhaps this is setting some defaults for class variables, creating other classes, or a variety of other items. I don’t need to do anything, so I’ve just left it blank.
After the Manager() you see the : base() construct. This tells the compiler “hey, before you run the constructor in Manger, go run the constructor in your base class, employee, then come back and run the Manager’s constructor”. Even though I don’t currently have any code in Employee’s constructor, one day I might. Plus if I’m following good encapsulation then I don’t know whether or not Employee has a constructor, nor do I care.
Using the base() keyword is not only common practice but a good idea. If you don’t, you’ll likely wind up on the side of the road, homeless holding a sign that reads “Will code() for food;”.
Enough on constructors, let’s look at a sample that uses our new Manager class.
Manager mgr1 = new Manager(); //Constructor runs here!
mgr1.FirstName = “Arcane”;
mgr1.Lastname = “Code”;
mgr1.MakeHairPointy();
MessageBox.Show(mgr1.FullName(), “Manager FullName Dialog”);
Even though you won’t find them in the code for the Manager class, you see I am calling FirstName, LastName, properties and the FullName method. The Manager inherited these from Employee.
Imagine you had not one or two types of employees, but fifty? Then imagine your boss wanted you to make a change to the FirstName property, so that if the length were only one character it automatically put a period at the end of the first name? Now you begin to see the power of inheritance.
You make your change to the Employee class, which is known as the base class. Recompile, and you are done. That change is automatically reflected in all of the child classes that inherit from the base Employee class.
What if you have a situation where you want to implement something in the base class in a slightly different way? You have the power to override the base classes implementation of that method. That’s a fancy way of saying you can create a method with the same name in your descended class, with your new code. But there’s a big “if” you need to know about. (Isn’t there always?)
When you create a method in a base class, you must use the virtual keyword in the method declaration. This flags the compiler that it’s OK to override in child classes. Without the virtual keyword, the compiler will produce errors and fail. So let’s fix our employee classes FullName method so we can override it later.
public virtual string FullName()
{
string returnValue;
returnValue = _firstname + ” “ + _lastname;
return returnValue;
}
All that was really needed was to slip the virtual keyword between the scope and the return type. Now we are ready to rewrite this method in our Manager class.
public override string FullName()
{
return “Oh great one “ + base.FirstName + ” “ + base.Lastname;
}
Now when I run my code, I will see the rewritten FullName for the manager appear.
Note too the use of the base.FirstName and base.LastName. Through the keyword base, you can access any of the non-private properties and methods of the base class. I could just have easily have done:
public override string FullName()
{
return “Oh great one “ + base.FullName();
}
If you take some time to plan your code architecture (see my post https://arcanecode.wordpress.com/2007/02/07/arcane-thoughts-the-passion-of-the-programmer/ or http://shrinkster.com/lvw) you can probably come up with many good relationships where you can go from abstract to something more concrete.
A real world example, in my database layer I descend all data handling classes from a base class that has common properties / methods such as the connection string and a connection object. This lets me write the connection “goo” once and use it over and over.
Don’t forget that at their heart, forms and toolbox items are classes as well, and you can inherit from them. A common technique is to override all of the common controls and use your version in your applications. The technique is slightly different so I will defer discussion on inheriting graphical stuff until another day.
A classic story I heard on DotNetRocks (http://www.dotnetrocks.com) is the lead developer who gets a call three days before their 300 form application is due to go to production. “Oh by the way” says the customer, “we forgot to mention it but it’s a requirement that all text boxes force their letters to uppercase.”
Even though they had not tweaked the text boxes previously, they had still made a decision lo those many months ago to inherit from the base text box and use the new one in their project. Because of that, they made a quick change to one routine in their custom text box, and all 300 forms were fixed in less than half an hour.
Inheritance can be an incredibly powerful tool when used correctly, but as my favorite hero Spider-Man used to say, “with great power comes great responsibility”. Make sure your inheritance chain is well thought out, lest you feel trapped in a spider’s web of your own making.