It should appear to us clearly by now that inheritance is
useful by allowing us to use an object that was already created but
"upgrade" it with new features that were not available when the
original object was born. In most cases, when creating a class, you may not
thing that other classes would be inherited from it. In fact, this will usually
not be your concern: you simply create a class and use it as needed.

In some
other cases, rather as you build your experience with Visual Basic. You may
create a class that, although useful at the time, you may already think of other
classes that would be based on it. This means that, at the time you are creating
such a class, you would already keep inheritance in mind. Visual Basic provides
various features that can assist you with creating and implementing class with
different goals in mind.

Abstracting a Class

Imagine that, when creating a class, you already find that
it is too or highly generalized to serve one particular purpose. As an example,
imagine you start creating a class you intend to use to process calculations for
a rectangle, or a square, or a parallelogram, or even a triangle:

Rectangle

Square

Parallelogram

Triangle

You start thinking that the same class could be used for
different types of geometric shapes. In this case, instead of creating a
different class for each shape, you can create a generalized class that these
shapes can be based on. Unfortunately, these shapes, although each characterized
as geometric, don't have much in common; otherwise they would not be different.
One of their common characteristics is that each has a name. While the
parallelogram and the triangle have a base, the rectangle and the square don't
explicitly have one. Also, neither the perimeter nor the area of these shapes
are calculated the same. Still, as long as you find at least one characteristic
that these objects have, you can create a class that would share. In other
words, you can create a class that features one or more characteristics that
these objects have. Then each object would customize its behavior(s) based on
its particular characteristics. This is the basis of abstraction.

A class is referred to as abstract when it is only used to
lay a foundation for other classes. In the Microsoft Visual Basic language, to
create an abstract class, you must precede its Class keyword with MustInherit.
Here is an example:

File: Quadrilateral.vb

Public MustInherit Class Quadrilateral
End Class

After creating a class and marking it as MustInherit,
you can add one or more members to it, as done in the previous examples we used
so far. Here is an example:

File: Quadrilateral.vb

Public MustInherit Class Quadrilateral
Public Function ShowDescription() As String
Return "Geometric Shape"
End Function
End Class

If you create a class and mark it as MustInherit, it is
considered incomplete. Because of that, although you can declare a variable of
that type, you cannot initialize its instance using the New operator. Consider
the following example:

File: Exercise.vb

This would produce an error because you cannot use New to
instantiate a MustInherit class. This means that, before using a MustInherit
class, you must derive a class from it.

Overriding Members of an Abstract Class

The main idea for creating a MustInherit class
is to lay a foundation that other classes can exploit. When creating the
members of such a class, you can prepare them to be overridden. You have
the option of creating overridable and non-overridable members. You will
make the decision based on your requirements.

Sometimes when creating a particular member, you may
intend all derived classes to implement their own version of the member.
You must clearly indicate that any class that wants to inherit from the MustInherit
class must (also) override a particular member. Such a member must be marked with
the MustOverride keyword. To do this, when creating the member,
precede its type with the MustOverride keyword. Here is an example:

File: Quadrilateral.vb

Public MustInherit Class Quadrilateral
Public MustOverride Property Area() As Double
End Class

In the same way, you can add as many members as
necessary. You will mark as MustOverride those of your choice and
you can create others without MustOverride. Here are examples:

File: Quadrilateral.vb

Public MustInherit Class Quadrilateral
Public Function ShowDescription() As String
Return "Geometric Shape"
End Function
Public MustOverride Property Area() As Double
End Class

After creating a MustInherit class, you can inherit new
classes from it using the Inherits keyword we saw in the previous lessons.
Here is an example:

Public Class Square
Inherits Quadrilateral
End Class

When deriving a class from a MustInherit, the
first rule you must observe is that each member of the abstract that was
marked as MustOverride must be overridden. Based on this, in our
Square class, you must (at least) implement the Area property. Here is
an example:

File: Quadrilateral.vb

Public MustInherit Class Quadrilateral
Public Function ShowDescription() As String
Return "Geometric Shape"
End Function
Public MustOverride ReadOnly Property Area() As Double
End Class
Public Class Square
Inherits Quadrilateral
Public Overrides ReadOnly Property Area() As Double
Get
Return 0
End Get
End Property
End Class

In the derived class, as a new one, you can add new
members as you judge them necessary. Here are examples:

File: Quadrilateral.vb

Public MustInherit Class Quadrilateral
Public Function ShowDescription() As String
Return "Geometric Shape"
End Function
Public MustOverride ReadOnly Property Area() As Double
End Class
Public Class Square
Inherits Quadrilateral
Public sd As Double
Public Sub New()
sd = 0
End Sub
Public Sub New(ByVal side As Double)
sd = side
End Sub
Public Property Side() As Double
Get
Return sd
End Get
Set(ByVal Value As Double)
If Value <= 0 Then
sd = 0
Else
sd = Value
End If
End Set
End Property
Public Overrides ReadOnly Property Area() As Double
Get
Return sd * sd
End Get
End Property
End Class

After deriving a new class from a MustInherit
class, you can declare a variable of it and instantiate it
using the New operator. Here is an example:

These declaration and instantiation are legal but the
(tri) variable gives you access only to members that are present in the
parent class. This means that this declaration gives you access to the
ShowDescription() method and the Area property of the Quadrilateral class. This is
illustrated in the following:

When instantiating a class derived from a MustInherit
class, if you want to access its members, you must apply its name to the New
operator as we saw in the last example of the previous section. Here is an example:

In Lesson 5, we saw that a procedure
was an assignment that complemented a program. We also saw that there were
two types of procedures: functions and sub routines. These concepts of sub
procedures and functions also apply to classes. This means that a
procedure that process a class, it can be passed a class as argument, and
it can return a class.

As described in Lesson 8, to create a sub procedure,
type the Sub
keyword followed by a name, followed by parentheses and an end of line. To
indicate the end of a sub procedure, you must type End Sub. Therefore, the
syntax of a sub procedure is:

SubProcedureName()
End Sub

Between the Sub and the End Sub lines, you can declare the
necessary variables and they can be of regular types or based on classes. Here
is an example:

In the same way, you can declare as many class variables as
you see fit in a procedure.

Returning an Object

So far, as we have learned since Lesson, we know that
a function can be used to return a value. In the same way, you can create
a function that returns an object of a class. When creating such a
function, set its type as that of the class it would return. The formula
to follow is still:

FunctionFunctionName() AsClassNameEnd Function

In the body of the class, which is the section between
the Function and the End Function lines, you can perform any assignment
you judge necessary. For example you can declare local variables. Before
exiting the function, you must make sure it returns a value based on its As
type. You can do this using the Return keyword followed by the value to
return. Here is an example:

Like a regular variable, a class can be passed as
argument to a procedure. When a procedure receives such an argument, it
can process it as necessary. All the rules we reviewed for regular
variables apply to a class, as long as you keep in mind that an object has
members that you may need to be aware of. When calling the procedure, make
sure you pass it a value argument based on the class it passed to it. Here
is an example of a class passed as argument:

Besides the function, in Lesson
5, we saw that, by passing an argument by reference, a sub procedure
could return a value. This characteristic also applies to a class passed
as argument. When passing the argument, precede it with the ByRef
keyword. In the procedure, process the argument as you see fit, unless you
choose not to. When calling the procedure, pass it a valid variable based
on the type of the argument. Here is an example:

Like a regular variable, a class can be locally
declared as static, using the Static keyword. If the value of
such a locally declared variable changes, when the procedure ends, the
value of the variable is changed and would be kept until the next call.

Optional Arguments

When passing an argument of a class, you can specify
that it is not required. Such an argument is considered optional. To specify that an argument is optional, when creating
its procedure, type the Optional keyword to the left of the
argument's name and assign it the default value. All the other rules we
reviewed for optional arguments are also applied here.

Procedure Overloading

If you want to create various procedures that takes a
class argument, you can create a procedure with the same name but
different signatures. This is referred to as overloading the procedure.
When doing this, follow the same rules we reviewed for overloading a
procedure: the must have the same name, they cannot have the same number
of argument when the arguments at each position are of the same types.

Sealed Classes

Introduction

All of the classes we have used so far can serve as
parents of other classes. This is the default behavior of a regular class:
the ability to derive a new class from it. In some cases, you may not want
any class to be derived from a particular class you are creating. Such a
class is referred to as sealed.

A class is said to be sealed when you cannot inherit
from it. If you try, you would receive an error. To create a sealed class
in Microsoft Visual Basic, precede the name of the class with the NotInheritable
keyword.