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

  1. To create the form shown in Figure 1, click Project, and then click Add Windows Form.

  2. Name the form frmLineTest.vb and click OK.

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

  1. From the menu, click Project, and then click Add Class.

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

  1. Click Project, and then click Add Class. Name the class LineDelim.vb and click OK.

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

  1. Open the frmLineTest.vb form.

  2. Double-click the GetWord button.

  3. 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
    
  4. 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.

  1. Add the two Private variables shown after the Inherits statement you added in the previous section.

    Private mstrDelim As String = " "
    Private mstrOriginal As String
    
  2. 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

  1. Open the form frmLineTest.vb.

  2. Double-click Replace to bring up the click event procedure.

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

  4. Press F5 to run the project.

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

  1. In the Solution Explorer window, open the code window for the Line.vb class.

  2. Locate the declaration for the GetWord method (the declaration that has no parameters) as shown below:

    Public Overloads Function GetWord() As String
    
  3. 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
    
  4. 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

  1. Run the project by pressing F5.

  2. Put a comma in between each word in the sentence, and fill in the Delimiter text box with a comma.

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

  1. Let's add a new class to the project you have created.

  2. From the Visual Studio menu, click Project and then click Add Class.

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

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