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 |