Inheritance from a Base Class in Microsoft .NET
Paul D. Sheriff
PDSA, Inc.
December 2001
Summary: This article explains inheritance, shows how to inherit from a base class, and describes implementation and interface inheritance in Microsoft .NET. (12 printed pages)
Objectives
- Overview of inheritance
- Learn how to inherit from a base class
- Learn about interface inheritance
- Learn about implementation inheritance
Assumptions
The following should be true for you to get the most out of this document:
- You understand basic coding
- You understand classes and how they work and/or have read the Creating Classes in .NET article
- You have access to Microsoft® Visual Basic® .NET
Contents
Overview of Inheritance
Inherit From a Base Class
Build the Sample Form
Create the Subclass
Add Additional Functionality
MyBase Keyword
Abstract Classes
Choosing the Type of Inheritance to Use
What's New Since Visual Basic 6.0?
Summary
Overview of Inheritance
One of the key features of Object Oriented Programming (OOP) languages is inheritance. Inheritance is the ability to use all of the functionality of an existing class, and extend those capabilities without re-writing the original class. Prior to the availability of Microsoft® Visual Basic® .NET, Visual Basic programmers did not have this capability. In Visual Basic .NET, you are able to inherit from classes that ship in the Microsoft .NET Framework, as well as from classes that you create. In this document, you will learn how to use inheritance, and see how it can significantly cut down your programming time.
A Simple Example
In many classes that you create, you will find that you often need the same properties and methods from another class that you created earlier. For example, if you have a base class called the Person class, and it contains LastName and FirstName properties and a Print method, you will find that for an Employee class, you need the same properties and methods. You may also need additional properties, such as EmployeeID and Salary. When you inherit from the Person class (the base class) you can add these properties to this new Employee class, and still have access to all of the properties in the Person class. Inheritance is about the ability for one class to define itself as having all the properties and methods of a particular class, and then extending the definition of the base class by adding additional properties and methods.
Inheritance Terminology
Before we delve too deeply into this topic, let's define a few terms. A new class that is created by inheritance is sometimes called a child class or a subclass. The class you originally inherited from is called the base class, parent class, or the superclass. In some OOP languages, a base class may inherit from more than one base class. This means that if you had a Person class and a Car class, a Driver class might inherit all of the properties and methods from each of these two classes. In the .NET world, only single inheritance is allowed, so each subclass will have only one base class.
There are three types of inheritance that .NET supports: implementation, interface, and visual. Implementation inheritance refers to the ability to use a base class's properties and methods with no additional coding. Interface inheritance refers to the ability to use just the names of the properties and methods, but the child class must provide the implementation. Visual inheritance refers to the ability for a child form (class) to use the base forms (class) visual representation as well as the implemented code.
A class in .NET may inherit from a class that has already inherited from another class. In addition you may use an interface or even multiple interfaces within a class.
Reasons for Using Inheritance
Inheritance is desirable because you want to avoid writing the same code over and over again. If you have two separate classes, and each one has to implement a FirstName and LastName property, you are going to have duplicate code. If you wish to change the implementation of one of these properties, you need to find all classes that have implemented these properties to make the changes. Not only is this time-consuming, but you also increase the risk of introducing bugs in the various classes.
One thing to remember when you are considering using inheritance is that the relationship between the two classes should be an "is a" type of relationship. For example, an Employee is a Person, and a Manager is a Person, so these two classes can inherit from the Person class. But you should not have a Leg class inherit from a Person class as a Leg is not a person.
Overriding
Once you start inheriting functionality from a base class, you might find that the generic method you wrote in the base class only performs part of what you need in the inheriting class. Instead of creating a whole new method, with a new name, to perform the full functionality that you want, you can override the base class' method in this new class.
When you override, you have the option of completely overriding the base class' method, or you can write some code to do something in the inheriting class and then call the base class' method. It is important that you when you override you still use the same contract, (the parameters and return type), of the original method. You may also choose to call the base class' method first, and then write additional code after the base class' method has finished executing.
Inherit From a Base Class
Inheritance gives you the ability to use all of the properties and methods from one class within another class. Instead of having to copy and paste code from one class to another, you use the keyword Inherits to get the functionality from the base class.
Implementation Inheritance
In this document, you will create a new class called LineDelim that will inherit all of the functionality from the Line class created in the Creating Classes in .NET article. You will extend the Line class by adding two additional properties and one method. The first property, Delimiter, will allow you to get and set a delimiter character into the class. This delimiter will be used to replace all of the spaces in the line to this delimiter character. The second property, OriginalLine, will be used to hold the original line of text, prior to inserting the new delimiter into the line of text. The new method you will create, ReplaceAll(), will replace all the spaces in the line with the delimiter character. You will then learn to override the GetWord method so it uses this delimiter instead of spaces to break up the line of text and search for the first word.
Build the Sample Form
The sample form shown in Figure 1 will be used to test the inherited class that you will create.
Figure 1. Sample form to test inheritance
To create the form shown in Figure 1, click Project, and then click Add Windows Form.
Name the form frmLineTest.vb and click OK.
Next create the appropriate controls on the form and set the properties as shown in Table 1.
Table 1: Form to test inheritance
Control Property Value Label Name Label1 Text Line of Text TextBox Name txtLine Text The rain in Spain stays mainly in the plain TextBox Name txtDelim Text , GroupBox Name fraWord Text Get First Word CommandButton Name btnFirst Text Get Word TextBox Name txtFirstWord Text ReadOnly True CommandButton Name btnReplace Text Replace TextBox Name txtReplace Text ReadOnly True
Build the Line Class
Next you build the Line class to inherit from.
From the menu, click Project, and then click Add Class.
Type in the code shown below.
Public Class Line Private mstrLine As String Property Line() As String Get Return mstrLine End Get Set(ByVal Value As String) mstrLine = Value End Set End Property ReadOnly Property Length() As Integer Get Return mstrLine.Length End Get End Property Public Function GetWord() As String Dim astrWords() As String astrWords = mstrLine.Split(" ".ToCharArray()) Return astrWords(0) End Function End Class
Create the Subclass
Now that you have the form and the base class created, it is time to start the inheritance process.
Click Project, and then click Add Class. Name the class LineDelim.vb and click OK.
Modify the code that Visual Basic .NET creates for you when you add the new class so that it looks like the sample shown below.
Public Class LineDelim Inherits Line End Class
You added the Inherits Line statement so that you can use all of the properties and methods of the Line class within this newly created class.
Try It Out
Open the frmLineTest.vb form.
Double-click the GetWord button.
Add the following code to the click event procedure for this button:
Protected Sub btnFirst_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles btnFirst.Click Dim oLine As LineDelim = New LineDelim() oLine.Line = txtLine.Text txtFirstWord.Text = oLine.GetWord() End Sub
Run the project, and on the form, click the GetWord button. You should see the word "The" appear in the read-only text box next to this button.
The Inherits statement is very powerful. With just one statement, you now have all of the properties and methods of the Line class available in the LineDelim class. Although this new class does not do anything new yet, it shows that all of the code works from the inherited Line class.
Add Additional Functionality
You can now extend the LineDelim class with additional properties and methods. Follow the steps below to add two new properties to the LineDelim class.
Add the two Private variables shown after the Inherits statement you added in the previous section.
Private mstrDelim As String = " " Private mstrOriginal As String
Type in the code below to add the appropriate Property statements for each of these Private variables. You may place this code immediately after the two lines you just entered above.
Public Property Delimiter() As String Get Return mstrDelim End Get Set(ByVal Value As String) mstrDelim = Value End Set End Property Public ReadOnly Property OriginalLine() As String Get Return mstrOriginal End Get End Property
You can now use the Delimiter property to both set and get the value from the Private variable mstrDelim.
Sometimes you may not want someone else to change one of your properties. In this case, you can make the property read-only. To do this, leave off the Set statement, and add the ReadOnly attribute to the Property statement. You can see an example of this in the declaration of the OriginalLine property shown in the code above.
Next, create a method called ReplaceAll that will replace all of the spaces in the line of text with the delimiter character passed into the Delimiter property.
Public Function ReplaceAll() As String
mstrOriginal = MyBase.Line
Return MyBase.Line.Replace(" ", mstrDelim.ToChar())
End Function
The ReplaceAll method retrieves the original line of text from the Line method of the base class. You used the MyBase.Line syntax to retrieve a property from the base class. The ReplaceAll function places the value of the MyBase.Line property into the Private variable, mstrOriginal, which you just created for this class. The Replace method of the String data type replaces all instances of a string character with the new delimiter character, mstrDelim, which you have set in the Delimiter property.
MyBase Keyword
The MyBase keyword can be used from any subclass to make a call to any property or method in the base class. You can even use it to call the base class' method that you have overridden in the subclass. For example, if you have a method in the base class called ReplaceAll, and you have overridden that method in the subclass, from within the ReplaceAll method in the subclass you may call the ReplaceAll method in the base class.
Try It Out
Open the form frmLineTest.vb.
Double-click Replace to bring up the click event procedure.
Write the code shown below in the click event for the btnReplace button.
Protected Sub btnReplace_Click( _ ByVal sender As Object, _ ByVal e As System.EventArgs) Handles btnReplace.Click Dim oLine As LineDelim = New LineDelim() oLine.Delimiter = txtDelim.Text oLine.Line = txtLine.Text txtReplace.Text = oLine.ReplaceAll() End Sub
This code will set the Delimiter property to a value entered into the txtDelimiter text box on the sample form. You then invoke the ReplaceAll method to change all of the spaces in the line of text to the new delimiter character.
Press F5 to run the project.
Click Replace. You should see a comma between each word of the sentence in the text box located next to the Replace button.
Override a Method
Now that you have added a Delimiter property, you might want to change the GetWord method in the LineDelim class to use that delimiter instead of the single space that the Line class uses. Because you don't necessarily want to change the base class, you will need to override the capabilities of the GetWord method in the LineDelim class. Before you can create a new GetWord method in the LineDelim class, you need to add a keyword to the GetWord method declaration in the Line class.
In the Solution Explorer window, open the code window for the Line.vb class.
Locate the declaration for the GetWord method (the declaration that has no parameters) as shown below:
Public Overloads Function GetWord() As String
Add the keyword Overridable to the function declaration, as shown in the listing below (without this keyword, you won't be able to override this method).
Public Overridable Overloads Function GetWord() As String
Open the LineDelim.vb class and add a new GetWord method using the code shown below.
Public Overloads Overrides Function GetWord() As String Dim astrWords() As String astrWords = MyBase.Line.Split(mstrDelim.ToCharArray()) Return astrWords(0) End Function
The Overrides keyword in the function declaration is necessary when you wish to change the functionality of a method from the base class. The GetWord method in the LineDelim class will now use the value of the Delimiter property to separate the words in a sentence.
One side effect of overriding just one of the GetWord methods is that your code can only see this one version of the method. Your code cannot call the other versions of the GetWord method. To make them all visible, you have to override each one, just like you did the LineDelim class.
Try It Out
Run the project by pressing F5.
Put a comma in between each word in the sentence, and fill in the Delimiter text box with a comma.
Click Get Word.
The first word in the sentence should now appear in the text box next to the Get Word button.
Abstract Classes
In an example from a previous section of this document, you learned to create a Person object because you wanted to deal with a generic person. But you may decide that there is nothing that you can really do with a Person class without first adding some specific behaviors, and/or data. So you make the Person class an abstract class that only defines the generic properties and methods that will be created by subclasses.
The Person class is defined to be an abstract class that can only be inherited from, not an object that is actually created at run time. Each class that inherits from this class, like the Employee class, will create all of the appropriate properties and methods with specific functionality. For example, the Employee class will create an actual Print method, whereas the Person class only defines that a Print method must exist; there is no code associated with the Print method in the Person class.
There are several reasons why you might wish to use an abstract class. They are great for enforcing that the designers of subclasses implement all of the interfaces normally needed by an application. You can add new methods to a child without breaking your client applications, something not possible with interfaces. You can provide a lot of default implementations in the base class to reduce the amount of work a child class has to do.
Interface Inheritance
When you want to create an abstract class, you use the keyword Interface instead of Class. You give the interface a name, and define each of the properties and methods that you expect a subclass to implement. The reason you do this is that there is nothing in the base class that would make sense to implement—it only contains generic data without methods. You are just creating a contract that says any subclass using this interface must adhere to certain rules.
Let's add a new class to the project you have created.
From the Visual Studio menu, click Project and then click Add Class.
Add the following code to this class:
Interface Person Property FirstName() As String Property LastName() As String Sub Print() Sub Talk() End Interface
You can see that you are defining properties and sub procedures just like you would normally define them. The only difference is that you don't fill in any code for them. Now, let's take a look at how you use this Interface in a class definition.
To the same class file that you created in the previous step, add the code you see below.
Public Class Employee Implements Person Private mstrFirstName As String Private mstrLastName As String Property FirstName() As String _ Implements Person.FirstName Get Return mstrFirstName End Get Set mstrFirstName = Value End Set End Property Property LastName() As String _ Implements Person.LastName Get Return mstrLastName End Get Set mstrLastName = Value End Set End Property Sub Print() Implements Person.Print ' Some code goes here End Sub Sub Talk() Implements Person.Talk ' Some code goes here End Sub End Class
The first line after the definition of the Employee class is Implements Person. This keyword says that you are adhering to the contract set forth in the Person Interface. Now you can define each of the properties and methods in that contract. After each Property statement, you must include the Implements keyword and specify the name of the Interface, a dot (.) and the name of the method/property you are implementing. Visual Basic .NET will keep track of each of these interfaces, and until each one of the interfaces is created, it will not allow you to compile the application.
If you want to run the code, you need to create the appropriate sub procedures, because they are left blank in the above sample. After you create each of these, you will be able to declare a new Employee object and use the Employee object just like any other object you normally create and use.
Choosing the Type of Inheritance to Use
Deciding whether to use Implementation or Interface inheritance is not always straightforward. In many cases, you might have to do a little of both. For example, you might add a method definition that must be overridden by a subclass to the Line class. You implement this by using the MustOverride keyword in a procedure definition.
Public MustOverride Sub Init()
When you add this definition to a Class, it acts similar to an Interface. In the subclass, the Init method must be defined, and it must use the Overrides keyword. Here is an example of how you might define this Init method:
Public Overrides Sub Init()
mstrDelim = " "
mstrLine = "Test Line"
End Sub
Once again, notice the use of the Overrides keyword to let the compiler know that this method is the one that overrides the Init method in the parent class.
Note
Check the online Help in the Microsoft .NET Framework for design guidelines to help you make decisions about the types of inheritance to use.
Stopping Inheritance
In some instances you may not wish other classes to be derived from your class. If this is the case, you can stop inheritance on a class by using the keyword NotInheritable.
Public Class NotInheritable Employee
' Class definition
End Class
What's New Since Visual Basic 6.0?
Using Visual Basic .NET, you can inherit from all the classes that ship with the .NET Framework. You can create your own classes that inherit from existing classes and add or remove functionality using simple changes to code.
Summary
In this document, you learned how to inherit from a base class. You added additional properties to the base class, and used the Overrides keyword to replace functionality defined in the base class. You also learned to use the MyBase keyword to call methods in the base class, thereby extending what the base class can do. Inheritance is not appropriate for all your applications, but you will find that used correctly it can be a powerful tool.
About the Author
Paul D. Sheriff is the owner of PDSA, Inc., a custom software development and consulting company in Southern California. Paul is the MSDN Regional Director for Southern California, is the author of a book on Visual Basic 6 called Paul Sheriff Teaches Visual Basic, and has produced over 72 videos on Visual Basic, SQL Server, .NET and Web Development for Keystone Learning Systems. Paul has co-authored a book entitled ASP.NET Jumpstart. Visit the PDSA, Inc. Web site (www.pdsa.com) for more information.
About Informant Communications Group
Informant Communications Group, Inc. (www.informant.com) is a diversified media company focused on the information technology sector. Specializing in software development publications, conferences, catalog publishing and Web sites, ICG was founded in 1990. With offices in the United States and the United Kingdom, ICG has served as a respected media and marketing content integrator, satisfying the burgeoning appetite of IT professionals for quality technical information.
Copyright © Informant Communications Group and Microsoft Corporation
Technical Editing: PDSA, Inc.