Introduction to Inheritance

Inheritance is a fundamental concept in Object-Oriented Programming (OOP) that allows you to define a class that takes on the attributes and behaviors of another class. The class from which you are deriving is called the base class (or parent class), and the class that is deriving is called the derived class (or child class).

In VB.NET, inheritance promotes code reusability and establishes a hierarchical relationship between classes. A derived class inherits public and protected members of its base class, allowing you to extend or modify the functionality of the base class without altering its original code.

Key Concepts

  • Base Class: The class that provides members to be inherited.
  • Derived Class: The class that inherits members from a base class.
  • "Is-A" Relationship: Inheritance models an "is-a" relationship. For example, a Car "is-a" Vehicle.
  • Code Reusability: Avoid duplicating code by defining common functionality in a base class.
  • Polymorphism: Inheritance is a prerequisite for certain forms of polymorphism, allowing objects of derived classes to be treated as objects of their base class.

Syntax and Implementation

To inherit from a class in VB.NET, you use the Inherits keyword.


' Base Class Definition
Public Class Animal
    Public Property Name As String

    Public Sub New(name As String)
        Me.Name = name
    End Sub

    Public Overridable Sub Speak()
        Console.WriteLine("The animal makes a sound.")
    End Sub
End Class

' Derived Class Definition
Public Class Dog
    Inherits Animal

    Public Sub New(name As String)
        MyBase.New(name) ' Call the base class constructor
    End Sub

    ' Override the Speak method
    Public Overrides Sub Speak()
        Console.WriteLine("Woof! My name is " & Name)
    End Sub

    Public Sub WagTail()
        Console.WriteLine(Name & " wags its tail.")
    End Sub
End Class
                

In this example, the Dog class inherits from the Animal class. It can access the Name property and call the Speak method inherited from Animal. The derived class can also introduce its own members, like the WagTail method.

Overriding Members

To allow a derived class to provide its own implementation of a method, property, or event defined in the base class, the member in the base class must be marked with the Overridable keyword. The corresponding member in the derived class must be marked with the Overrides keyword.

Using Overrides allows you to change the behavior of a base class member while maintaining the original signature. You can access the base class implementation within the overridden method using the MyBase keyword.

Example: Accessing Base Class Method


Public Class Cat
    Inherits Animal

    Public Sub New(name As String)
        MyBase.New(name)
    End Sub

    Public Overrides Sub Speak()
        MyBase.Speak() ' Call the base Animal's Speak method first
        Console.WriteLine("Meow! I am " & Name)
    End Sub
End Class
                    

Shadowing Members

Shadowing is an alternative to overriding. When a member in a derived class has the same name as a member in a base class, but the base class member is not marked as Overridable, the derived class member shadows the base class member. The derived class member is used when accessed through an instance of the derived class, effectively hiding the base class member.

Use the Shadows keyword to explicitly indicate shadowing.

Example: Shadowing a Property


Public Class BaseClass
    Public Property Data As Integer = 10
End Class

Public Class DerivedClass
    Inherits BaseClass
    ' Shadows the Data property from BaseClass
    Public Shadows Property Data As Integer = 20

    Public Sub DisplayData()
        Console.WriteLine("Derived Data: " & Me.Data) ' Accesses derived property
        Console.WriteLine("Base Data: " & MyBase.Data) ' Accesses base property
    End Sub
End Class
                    

It's generally recommended to use Overridable and Overrides for polymorphism, while Shadows is for hiding members when you don't want to participate in polymorphism.

Abstract Classes and Methods

An Abstract class is a class that cannot be instantiated directly. It is intended to be used as a base class. Abstract classes can contain abstract members.

An Abstract member (method, property, etc.) is declared in an abstract class but does not have an implementation. Derived classes that are not themselves abstract must provide an implementation for all inherited abstract members.


Public MustInherit Class Shape
    Public MustOverride Function CalculateArea() As Double
    Public Overridable Function GetDescription() As String
        Return "This is a shape."
    End Function
End Class

Public Class Circle
    Inherits Shape

    Public Property Radius As Double

    Public Sub New(radius As Double)
        Me.Radius = radius
    End Sub

    ' Must implement the abstract function
    Public Overrides Function CalculateArea() As Double
        Return Math.PI * Radius * Radius
    End Function

    Public Overrides Function GetDescription() As String
        Return "This is a circle with radius " & Radius
    End Function
End Class
                

Sealed Classes

A Sealed class (or NotInheritable in VB.NET) cannot be used as a base class. Any attempt to inherit from a sealed class will result in a compile-time error. This is useful when you want to prevent further extension of a class, either for security reasons or because you consider the class complete.


Public NotInheritable Class UtilityHelper
    Public Shared Function FormatString(input As String) As String
        Return input.Trim().ToUpper()
    End Function
End Class

' This will cause a compile error:
' Public Class MyUtility
'     Inherits UtilityHelper
' End Class
                

Best Practices

  • Favor Composition over Inheritance: While inheritance is powerful, sometimes creating relationships where one class "has-a" object of another class (composition) is more flexible and less prone to tight coupling.
  • Design for Inheritance: If you design a class to be inherited, make sure its members are appropriately marked with Public, Protected, Overridable, etc.
  • Document Clearly: Clearly document which members are intended to be overridden and how they should be used.
  • Use `MyBase` and `MyClass` Wisely: Understand when to call base class implementations (MyBase) and when to refer to the current class's members (MyClass).
  • Avoid Deep Inheritance Hierarchies: Very deep inheritance chains can become complex and difficult to manage.