The Shape base class and the Shapes derived class work fine, but there’s a potential problem. A new derived class that implements a new shape may not override the Area or the Perimeter method. If you want to force all derived classes to implement a specific method, you can specify the MustInherit modifier for the class declaration and the MustOverride modifier for the member declaration. If some of the derived classes may not provide their implementation of a method, this method of the derived class must also be declared with the Overridable keyword.
The Shapes project uses the MustInherit keyword in the definition of the Shape class. This keyword tells the CLR that the Shape class can’t be used as is; it must be inherited by another class. A class that can’t be used as is, is known as an abstract base class, or a virtual class. The definition of the Area and Perimeter methods are prefixed with the MustOverride keyword, which tells the compiler that derived classes (the ones that will inherit the members of the base class) must provide their own implementation of the two methods:
Public MustInherit Class Shape
Public MustOverride Function Area() As Double
Public MustOverride Function Perimeter() As Double
Notice that there’s no End Function statement, just the declaration of the function that must be inherited by all derived classes. If the derived classes may override one or more methods optionally, these methods must be implemented as actual functions. Methods that must be overridden need not be implemented as functions — they’re just placeholders for a name. You must also specify their parameters, if any. The definitions of the methods you specify are known as the methods’ signature.
There are other modifiers you can use with your classes, such as the NotInheritable modifier, which prevents your class from being used as a base class by other developers. The System.Array class is an example of a Framework class can’t be inherited.
In the following section, you’ll look at the class-related modifiers and learn when to use them. The various modifiers are keywords, such as the Public and Private keywords that you can use in variable declarations. These keywords can be grouped according to the entity they apply to, and I used this grouping to organize them in the following sections.
Parent Class Keywords
These keywords apply to classes that can be inherited, and they appear in front of the Class keyword. By default, all classes can be inherited, but their members can’t be overridden. You can change this default behavior with the following modifiers:
NotInheritable – This prevents the class from being inherited. The base data types, for example, are not inheritable. In other words, you can’t create a new class based on the Integer data type. The Array class is also not inheritable.
MustInherit – This class must be inherited. Classes prefixed with the MustInherit attribute are called abstract classes, and the Framework contains quite a few of them. You can’t create an object of this class in your code and, therefore, you can’t access its methods. The Shape class is nothing more than a blueprint for the methods it exposes and can’t be used on its own; that’s why it was declared with the MustInherit keyword.
Derived Class Keywords
The following keywords may appear in a derived class; they have to do with the derived class’s parent class:
Inherits – Any derived class must inherit an existing class. The Inherits statement tells the compiler which class it derives from. A class that doesn’t include the Inherits keyword is by definition a base class.
MyBase – Use the MyBase keyword to access a derived class’s parent class from within the derived class’s code.
Parent Class Member Keywords
These keywords apply to the members of classes that can be inherited, and they appear in front of the member’s name. They determine how derived classes must handle the members (that is, whether they can or must override their properties and methods):
Overridable – Every member with this modifier can be overwritten. If a member is declared as Public only, it can’t be overridden. You should allow developers to override as many of the members of your class as possible, as long as you don’t think there’s a chance that they might break the code by overriding a member. Members declared with the Overridable keyword don’t necessarily need to be overridden, so they must provide some functionality.
NotOverridable – Every member declared with this modifier can’t be overridden in the inheriting class.
MustOverride – Every member declared with this modifier must be overridden. You can skip the overriding of a member declared with the MustOverride modifier in the derived class, as long as the derived class is declared with the MustInherit modifier. This means that the derived class must be inherited by some other class, which then receives the obligation to override the original member declared as MustOverride.
The two methods of the Shape class must be overridden, and we’ve done so in all the derived classes that implement various shapes. Let’s also assume that you want to create different types of triangles with different classes (an orthogonal triangle, an isosceles triangle, and a generic triangle). Let’s also assume that these classes would inherit the Triangle class. You can skip the definition of the Area method in the Triangle class, but you’d have to include it in the derived classes that implement the various types of triangles. Moreover, the Triangle class would have to be marked as MustInherit.
Public – This modifier tells the CLR that the specific member can be accessed from any application that uses the class. This, as well as the following keywords, are access modifiers and are strictly inheritance related, but I’m listing them here for completeness.
Private – This modifier tells the CLR that the specific member can be accessed only in the module in which it was declared. All the local variables must be declared as Private, and no other class (including derived classes) or application will see them.
Protected – Protected members have scope between public and private, and they can be accessed in the derived class, but they’re not exposed to applications using either the parent class or the derived classes. In the derived class, they have a private scope. Use the Protected keyword to mark the members that are of interest to developers who will use your class as a base class, but not to developers who will use it in their applications.
Protected Friend – This modifier tells the CLR that the member is available to the class that inherits the class, as well as to any other component of the same project.
Derived Class Member Keyword
The Overrides keyword applies to members of derived classes and indicates whether a member of the derived class overrides a base class member. Use this keyword to specify the member of the parent class you’re overriding. If a member has the same name in the derived class as in the parent class, this member must be overridden. You can’t use the Overrides keyword with members that were declared with the NotOverridable or Protected keywords in the base class.
The InheritanceKeywords Example
A few examples are in order. The sample application of this section is the InheritanceKeywords project, and it contains a few classes and a simple test form. Create a simple class by entering the statements of Listing 7.11 in a Class module, and name the module ParentClass.
Listing 7.11: InheritanceKeywords Class
Public MustInherit Class ParentClass
Public Overridable Function Method1() As String
Return ("I'm the original Method1")
Protected Function Method2() As String
Return ("I'm the original Method2")
Public Function Method3() As String
Return ("I'm the original Method3")
Public MustOverride Function Method4() As String
' No code in a member that must be overridden !
' Notice the lack of the matching End Function here
Public Function Method5() As String
Return ("I'm the original Method5")
Private prop1, prop2 As String
Property Property1() As String
Property1 = "Original Property1"
prop1 = Value
Property Property2() As String
Property2 = "Original Property2"
prop2 = Value
This class has five methods and two properties. Notice that Method4 is declared with the MustOverride keyword, which means it must be overridden in a derived class. Notice also the structure of Method4. It has no code, and the End Function statement is missing. Method4 is declared with the MustOverride keyword, so you can’t instantiate an object of the ParentClass type. A class that contains even a single member marked as MustOverride must also be declared as MustInherit.
Place a button on the class’s test form, and in its code window attempt to declare a variable of the ParentClass type. VB will issue a warning that you can’t create a new instance of a class declared with the MustInherit keyword. Because of the MustInherit keyword, you must create a derived class. Enter the lines from Listing 7.12 in the ParentClass module after the end of the existing class.
Listing 7.12: Derived Class
Public Class DerivedClass
Overrides Function Method4() As String
Return ("I'm the derived Method4")
Public Function newMethod() As String
Console.WriteLine("<This is the derived Class's newMethod " & _
"calling Method2 of the parent Class> ")
Console.WriteLine(" " & MyBase.Method2())
The Inherits keyword determines the parent class. This class overrides the Method4 member and adds a new method to the derived class: newMethod. If you switch to the test form’s code window, you can now declare a variable of the DerivedClass type:
Dim obj As DerivedClass
This class exposes all the members of ParentClass except for the Method2 method, which is declared with the Protected modifier. Notice that the newMethod() function calls this method through the MyBase keyword and makes its functionality available to the application. Normally, we don’t expose Protected methods and properties through the derived class.
Let’s remove the MustInherit keyword from the declaration of the ParentClass class. Because it’s no longer mandatory that the ParentClass be inherited, the MustInherit keyword is no longer a valid modifier for the class’ members. So, Method4 must be either removed or implemented. Let’s delete the declaration of the Method4 member. Because Method4 is no longer a member of the ParentClass, you must also remove the entry in the DerivedClass that overrides it.