An implementing class is free to mark any or all of the methods that implement the interface as overridable. Derived classes can then override or provide new implementations. For example, a Document class might implement the IStorable interface and mark the Read() and Write( ) methods as overridable. The Document might Read( ) and Write( ) its contents to a File type. The developer might later derive new types from Document, such as perhaps a Note or EmailMessage type. While the Document class implements Read( ) and Write to save to a File, the Note class might implement Read( ) and Write( ) to read from and write to a database.
Example 8-5 strips down the complexity of the previous examples and illustrates overriding an interface implementation. In this example, you'll derive a new class named Note from the Document class.
Document implements the IStorable-required Read( ) method as an overridable method, and Note overrides that implementation.
|
The complete listing is shown in Example 8-5 and analyzed in detail following.
Option Strict On
Imports Microsoft.VisualBasic
Imports System
Namespace OverridingInterfaces
Interface IStorable
Sub Read( )
Sub Write( )
End Interface
' simplify Document to implement only IStorable
Public Class Document : Implements IStorable
' the document constructor
Public Sub New(ByVal s As String)
Console.WriteLine("Creating document with: {0}", s)
End Sub
' make read virtual
Public Overridable Sub Read( ) Implements IStorable.Read
Console.WriteLine("Document Virtual Read Method for IStorable")
End Sub
' NB: Not virtual!
Public Sub Write( ) Implements IStorable.Write
Console.WriteLine("Document Write Method for IStorable")
End Sub
End Class
' derive from Document
Public Class Note : Inherits Document
Public Sub New(ByVal s As String)
MyBase.New(s)
Console.WriteLine("Creating note with: {0}", s)
End Sub
' override the Read method
Public Overrides Sub Read( )
Console.WriteLine("Overriding the Read method for Note!")
End Sub
' implement my own Write method
Public Shadows Sub Write( )
Console.WriteLine("Implementing the Write method for Note!")
End Sub
End Class
Class Tester
Public Sub Run( )
' create a Document object
Dim theNote As Document = New Note("Test Note")
' cast the Document to IStorable
If TypeOf theNote Is IStorable Then
Dim isNote As IStorable = theNote
isNote.Read( )
isNote.Write( )
End If
Console.WriteLine(vbCrLf)
' direct call to the methods
theNote.Read( )
theNote.Write( )
Console.WriteLine(vbCrLf)
' create a note object
Dim note2 As New Note("Second Test")
' Cast the note to IStorable
If TypeOf note2 Is IStorable Then
Dim isNote2 As IStorable = note2
isNote2.Read( )
isNote2.Write( )
End If
Console.WriteLine(vbCrLf)
' directly call the methods
note2.Read( )
note2.Write( )
End Sub
Public Shared Sub Main( )
Dim t As New Tester( )
t.Run( )
End Sub
End Class
End Namespace
Output:
Creating document with: Test Note
Creating note with: Test Note
Overriding the Read method for Note!
Document Write Method for IStorable
Overriding the Read method for Note!
Document Write Method for IStorable
Creating document with: Second Test
Creating note with: Second Test
Overriding the Read method for Note!
Document Write Method for IStorable
Overriding the Read method for Note!
Implementing the Write method for Note!
In Example 8-5, the IStorable interface is simplified for clarity's sake:
Interface IStorable
Sub Read( )
Sub Write( )
End Interface
The Document class implements the IStorable interface:
Public Class Document : Implements IStorable
The designer of Document has opted to make the Read( ) method overridable but not to make the Write( ) method overridable:
Public Overridable Sub Read( ) Implements IStorable.Read
Public Sub Write( ) Implements IStorable.Write
|
The new class, Note, derives from Document:
Public Class Note : Inherits Document
It is not necessary for Note to override Read( ) (it may shadow it instead), but it is free to do so and has done so here:
Public Overrides Sub Read( )
To illustrate the implications of marking an implementing method as overridable, the Run( ) method calls the Read( ) and Write( ) methods in four ways:
Through the base class reference to a derived object
Through an interface created from the base class reference to the derived object
Through a derived object
Through an interface created from the derived object
As you'll see, the base class reference and the derived class reference act just as they always have: overridable methods are implemented polymorphically and non-overridable methods are not. The interfaces created from these references work just like the references themselves: overridable implementations of the interface methods are polymorphic, and non-overridable methods are not.
The one surprising aspect is this: when you call the non-polymorphic Write( ) method on the IStorable interface cast from the derived Note, you actually get the Document's Write( ) method. This is because Write( ) is implemented in the base class and is not overridable.
To accomplish the first two calls, a Document (base class) reference is created, and the address of a new Note (derived) object created on the heap is assigned to the Document reference:
Dim theNote As Document = New Note("Test Note")
An interface reference is created (isNote) and theNote is cast to the IStorable interface:
If TypeOf theNote Is IStorable Then
Dim isNote As IStorable = theNote
You then invoke the Read( ) and Write( ) methods through that interface. The output reveals that the Read( ) method is responded to polymorphically and the Write( ) method is not, just as you would expect:
Overriding the Read method for Note! Document Write Method for IStorable
The Read( ) and Write( ) methods are then called directly on the derived object itself:
theNote.Read( ) theNote.Write( )
and once again you see the polymorphic implementation has worked:
Overriding the Read method for Note! Document Write Method for IStorable
In both cases, the Read( ) method of Note was called, but the Write( ) method of Document was called.
To prove to yourself that this is a result of the overriding method, you next create a second Note object, this time assigning its address to a reference to a Note. This will be used to illustrate the final cases (i.e., a call through a derived object and a call through an interface created from the derived object):
Dim note2 As New Note("Second Test")
Once again, when you cast to a reference, the overridden Read( ) method is called. When, however, methods are called directly on the Note object:
note2.Read( ) note2.Write( )
the output reflects that you've called a Note and not an overridden Document:
Overriding the Read method for Note! Implementing the Write method for Note!
|
|
| Top |