Visual Basic 2012 Voorbeelden
   

visual basic 2012 broncode voorbeelden

Blijf op de hoogte van de recente aanpassingen op vbvoorbeelden!

Microsoft Visual Studio 2012Microsoft Developers Network - Visual BasicMicrosoft .NET Framework

9.15. Redefinition - Overridable en Overrides

Print Email Deel op Twitter Deel op Facebook

Dit artikel is gepubliceerd op maandag 15 oktober 2012 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.

9.15.1. Overridable en Overrides

Wanneer men aan een overgeërfde member een andere implementatie wenst te koppelen kan men deze overgeërfde member gaan herdefiniëren.  Dit wordt ook wel "redefinition" of in de context van Visual Basic "overriding" genoemd.

Een vereiste is wel dat de member die je wenst te herdefiniëren in de basisklasse als herdefinieerbaar staat aangegeven.
Dit kan door in de signatuur van deze member het Overridable keyword op te nemen.

De member wordt herhaald in de klassen die aan deze member een andere implementatie willen koppelen en staat daar als herdefinitie aangegeven.  Wat men bekomt door aan de signatuur van deze herdefinitie het Overrides keyword toe te voegen.
Visual Basic 2012 Broncode - Codevoorbeeld 284
Class Class1
    Public Overridable Function Method1() As String
        Method1 = "Class1.Method1()"
    End Function
End Class
Class Class2 : Inherits Class1
    Public Overrides Function Method1() As String
        Method1 = "Class2.Method1()"
    End Function
End Class
Module Example1
    Sub Main()
        Dim object1 As Class1 = New Class1
        Console.WriteLine(object1.Method1())                               ' (1)
        '
        Dim object2 As Class2 = New Class2
        Console.WriteLine(object2.Method1())                               ' (2)
        '
        Console.ReadLine()
    End Sub
End Module
Console Application Output
Class1.Method1()
Class2.Method1()
Tijdens uitvoering van de client zal de aanroep op regel (1) "Class1.Method1()" als resultaat geven, en dit omdat object1 een object is van het type Class1.
Regel (2) zal dan als uitvoer "Method1 defined in Class2" geven, gezien de expressie object2 verwijst naar een object van het type Class2.

Vergeet het keyword Overrides niet in de signatuur van de herdefiniërende member, anders bekomt men geen redefinition maar shadowing.

Redefinition houdt dus steeds in dat een andere implementatie wordt gekoppeld aan de interface (lees aanwezigheid) van die member in een bepaald afgeleid type.  Het spreekt dan ook voor zich dat enkel implementatiemembers (properties en methods) kunnen geherdefinieerd worden.

Velden bijvoorbeeld die niet beschikken over een implementatie, kunnen bijgevolg ook niet gekoppeld worden aan een andere implementatie, redefinition van velden is dan ook onmogelijk.

Ook Private members kunnen niet worden geherdefinieerd.  Private members worden overgeërfd maar zijn niet aanroepbaar in afgeleide types, dus moet men geen andere implementatie kunnen koppelen aan die members wanneer die worden aangeroepen op of door een object van een afgeleid type.

De Public en Protected members zijn wel aanroepbaar in of op objecten van een afgeleid type, dus kan het wel nuttig zijn om aan deze aanroep een andere betekenis (implementatie) te gaan koppelen.

9.15.2. NotOverridable

Een overschrijvende (herdefiniërende) members is zelf by default ook overschrijfbaar (herdefinieerbaar).  Of met ander woorden Overrides impliceert ook Overridable.
Zo zal in onderstaand voorbeeld de herdefinitie (1) van Method1 zonder argumenten in Class4, ook nog eens geherdefinieerd worden in Class5, en dit zonder dat in Class4 Method1 expliciet als Overridable stond gemarkeerd.

Wenst men dit default gedrag aan te passen, dan kan men in de signatuur het NotOverridable keyword aan het Overrides keyword gaan toevoegen.

In onderstaand voorbeeld zal Method1 (met 1 argument) uit Class4 niet herdefinieerbaar zijn in Class5.
Visual Basic 2012 Broncode - Codevoorbeeld 285
Class Class3
    Public Overridable Function Method1() As String
        Method1 = "Class3.Method1()"
    End Function
    Public Overridable Function Method1(ByVal argument As String) As String
        Method1 = "Class3.Method1(" & argument & ")"
    End Function
End Class
Class Class4 : Inherits Class3
    Public Overrides Function Method1() As String ' (1)
        Method1 = "Class4.Method1()"
    End Function
    Public NotOverridable Overrides Function Method1(ByVal argument As String) _
                                                                       As String
        Method1 = "Class4.Method1(" & argument & ")"
    End Function
    Public Overloads Function Method1(ByVal argument1 As String, _
                                      ByVal argument2 As String) As String
        Method1 = "Class4.Method1(" & argument1 & "," & argument2 & ")"
    End Function
End Class
Class Class5 : Inherits Class4
    Public Overrides Function Method1() As String
        Method1 = "Class5.Method1()"
    End Function
End Class
Module Example2
    Sub Main()
        Dim object1 As Class3 = New Class3
        Console.WriteLine(object1.Method1())
        Console.WriteLine(object1.Method1("test"))
        '
        Dim object2 As Class4 = New Class4
        Console.WriteLine(object2.Method1())
        Console.WriteLine(object2.Method1("test"))
        Console.WriteLine(object2.Method1("test1", "test2"))
        '
        Dim object3 As Class5 = New Class5
        Console.WriteLine(object3.Method1())
        Console.WriteLine(object3.Method1("test"))
        Console.WriteLine(object3.Method1("test1", "test2"))
        '
        Console.ReadLine()
    End Sub
End Module
Console Application Output
Class3.Method1()
Class3.Method1(test)
Class4.Method1()
Class4.Method1(test)
Class4.Method1(test1,test2)
Class5.Method1()
Class4.Method1(test)
Class4.Method1(test1,test2)
In Class4 werd een extra versie van Method1 toegevoegd (met 2 argumenten), vergeet men hierbij het keyword Overloads te vermelden, dan krijgt men een compileerfout.
Een extra versie van een overgeërfde member die men wil toevoegen aan een afgeleide klasse moet immers altijd met het Overloads keyword gemarkeerd worden.

Hieronder een context voorbeeld waar geïllustreerd wordt dat het koppelen van een andere betekenis (of implementatie) aan een member nut kan hebben voor afgeleide klassen.

We beschikken over een Counter klasse, die bruikbaar is om een Value met 1 te incrementeren (Raise) of met 1 te decrementeren (Lower).
Visual Basic 2012 Broncode - Codevoorbeeld 286
Class Counter
    Protected _Value As Integer
    Public ReadOnly Property Value() As Integer
        Get
            Value = _Value
        End Get
    End Property
    Public Overridable Sub Raise()
        _Value += 1
    End Sub
    Public Overridable Sub Lower()
        _Value -= 1
    End Sub
End Class
Module Example3
    Sub Main()
        Dim counter As Counter = New Counter
        Console.WriteLine(counter.Value)
        counter.Raise()
        Console.WriteLine(counter.Value)
        counter.Raise()
        Console.WriteLine(counter.Value)
        counter.Lower()
        Console.WriteLine(counter.Value)
        '
        Console.ReadLine()
    End Sub
End Module
Console Application Output
0
1
2
1
Het schiet ons te binnen dat we ook een soort van Counter zouden kunnen gebruiken waar niet steeds stap waarde 1 wordt gebruikt om de Value te verhogen of verlagen.

We beslissen hiervoor een type SpecialCounter te creëren.

Het dringt tot ons door dat we SpecialCounter kunnen afleiden van Counter.  Een SpecialCounter IS tenslotte een specialisatie van de Counter die we reeds hebben, en SpecialCounter kan de aanwezigheid van alle members uit Counter gebruiken.

Gezien een stapwaarde moet kunnen worden gebruikt door onze SpecialCounter objecten, beslissen we een StepValue eigenschap toe te voegen aan deze afgeleide klasse.

Het gedrag (dat we ook overerven van Counter) dat ervoor zorgt dat bij het verhogen (Raise) of verlagen (Lower) steeds de Value met 1 respectievelijk gaat incrementeren of decrementeren, moet echter aangepast worden.  De (aanwezigheid van de) Raise- en Lower methods zijn/is nuttig voor SpecialCounter, enkel het gedrag ervan (of dus de implementaties) zijn voor het gespecialiseerde type niet bruikbaar en moet gewijzigd/geherdefinieerd worden.
Visual Basic 2012 Broncode - Codevoorbeeld 287
Class SpecialCounter : Inherits Counter
    Public Property StepValue As Integer = 1
    Public Overrides Sub Raise()
        _Value += StepValue
    End Sub
    Public Overrides Sub Lower()
        _Value -= StepValue
    End Sub
End Class
Hadden we in eerste instantie de Raise- en Lower methods niet Overridable gedefinieerd, dan was het niet mogelijk om het gedrag van deze methods te wijzigen in afgeleide klassen.

Men dient er zich dus steeds bij stil te staan (bij het creëren van een afleidbare basisklasse) of het nuttig kan zijn dat afgeleiden bepaalde implementatiemembers gaan herdefiniëren.  Is dit nuttig, markeer die member dan meteen als herdefinieerbaar (Overridable).

Het zelfde kan gesteld worden voor de access modifiers die je gebruikt in de afleidbare basisklassen.  Gezien de Raise- en Lower methods herdefinieerbaar werden gedefinieerd in Counter en gezien deze methods de waarde van het veld _Value (de toestand Value) aanpassen, is het ook logisch de velden (hier veld _Value) die mogelijk gemanipuleerd worden door die herdefinieerbare members beschikbaar te maken voor de afgeleiden.
Bij ingekapselde members kan dit bijvoorbeeld door access modifier Protected te gebruiken.
Visual Basic 2012 Broncode - Codevoorbeeld 288
Module Example4
    Sub Main()
        Dim specialCounter As SpecialCounter = New SpecialCounter
        Console.WriteLine(specialCounter.Value)
        specialCounter.StepValue = 5
        specialCounter.Raise()
        Console.WriteLine(specialCounter.Value)
        specialCounter.Raise()
        Console.WriteLine(specialCounter.Value)
        specialCounter.Lower()
        Console.WriteLine(specialCounter.Value)
        '
        Console.ReadLine()
    End Sub
End Module
Console Application Output
0
5
10
5

9.15.3. System.Object.ToString()

We weten reeds dat elke klasse op zen minst een afgeleide is van het algemeen overkoepelend basistype System.Object.  Wordt er niet expliciet een Inherits clausule toegevoegd aan een klassedefinitie, dan wordt er immers Inherits System.Object aan toegevoegd.

Een afgeleide klasse erft de members over van de basisklasse.

Type System.Object is niet leeg, met andere woorden van System.Object zullen bepaalde members worden overgeërfd.
Een voorbeeld van dergelijke overgeërfde member is : Public Overridable Function ToString() As String.  Deze member heeft als defaultgedrag dat het de "fully-qualified-identifier" van de klasse (volledige naam van de klasse, inclusief onderdeel waarin die klasse is gedefinieerd) oplevert (1).

Maar omdat die overgeërfde members als Overridable staat gedefinieerd, kunnen we ook dit gedrag aanpassen in afgeleide klassen.  De Student klasse bijvoorbeeld die van de Person klasse deze Overridable ToString() overerft, kan deze function overschrijven of dus koppelen aan een andere implementatie (2).
Visual Basic 2012 Broncode - Codevoorbeeld 289
Class Person
    Public Sub New(ByVal name As String)
        Me.Name = name
    End Sub
    Public Property Name As String
End Class
Class Student : Inherits Person
    Public Sub New(ByVal name As String, ByVal classGroup As String)
        MyBase.New(name)
        Me.ClassGroup = classGroup
    End Sub
    Public Property ClassGroup As String
    Public Overrides Function ToString() As String                         ' (2)
        ToString = Name & " (" & ClassGroup & ")"
    End Function
End Class
Module Example5
    Public Sub Main()
        Dim person1 As Person = New Person("John")
        Console.WriteLine(person1.ToString())                              ' (1)
        '
        Dim student1 As Student = New Student("Jane", "Visual Basic")
        Console.WriteLine(student1.ToString())                             ' (2)
        '
        Console.ReadLine()
    End Sub
End Module
Console Application Output
(*).Person
Jane (Visual Basic)
(*) Hier staat de na(a)m(en) van de namespace(s) waarin de klasse Person is gedefinieerd.

9.15.4. MyBase

Regelmatig komt het voor dat je in een herdefinitie het te herdefiniëren gedrag eerder wil uitbreiden dan vervangen.

De mogelijkheid bestaat in de implementatie van een herdefiniërende/overschrijvende member (Overrides member) de te herdefiniëren/overschrijven member (Overridable member) aan te roepen.  Men kan dit door het MyBase keyword te laten voorafgaan aan de identifier van de te herdefiniëren/overschrijven member.
Visual Basic 2012 Broncode - Codevoorbeeld 290
Partial Class Counter
    Public Overrides Function ToString() As String
        ToString = Value.ToString()
    End Function
End Class
Partial Class SpecialCounter
    Public Overrides Function ToString() As String
        ToString = MyBase.ToString() & " - Step : " & StepValue.ToString() ' (1)
    End Function
End Class
Module Example6
    Sub Main()
        Dim counter1 As Counter = New Counter
        Console.WriteLine(counter1.ToString())
        '
        Dim specialCounter1 As SpecialCounter = New SpecialCounter
        Console.WriteLine(specialCounter1.ToString())
        '
        Console.ReadLine()
    End Sub
End Module
Console Application Output
0
0 - Step : 1
De ToString() implementatie van SpecialCounter herbruikt hier nu de ToString() van Counter (1) (MyBase.ToString()), en breidt het resultaat ervan uit om tot zijn eigen resultaat te komen.

We hadden hetzelfde resultaat kunnen bekomen door regel (1) te vervangen door : ToString = Value.ToString() & " - Step : " & StepValue.ToString()

Hierbij wordt echter de ToString() van de basis klasse niet herbruikt, maar eerder gekopieerd.  Een wijziging aan de ToString() van Counter zal dan geen effect hebben naar het resultaat van een ToString() op een SpecialCounter object.

Welke werkwijze te verkiezen valt, hangt af van de vereisten.

9.15.5. Oefeningen

Opgave 1 :

Zorg dat we objecten voor "employees" kunnen creëren.  Een employee heeft een bepaald maandloon en een jaarloon (dat 12 keer het maandloon is)

Zorg er ook voor dat we objecten voor "managers" kunnen creëren.  Een manager is een employee, met eigenschappen maandloon, premie en jaarloon.
Het jaarloon van een manager wordt net zo berekend als van een gewone employee, met als verschil dat daar nog de premie wordt bij opgeteld.
Oplossing 1 :
Visual Basic 2012 Broncode - Codevoorbeeld 291
Class Employee
    Public Property MonthlySalary As Decimal
    Public Overridable Function GetYearlySalary() As Decimal
        GetYearlySalary = MonthlySalary * 12
    End Function
End Class
Class Manager : Inherits Employee
    Public Property Bonus As Decimal
    Public Overrides Function GetYearlySalary() As Decimal
        GetYearlySalary = MyBase.GetYearlySalary() + Bonus
    End Function
End Class
Module Exercise1Solution
    Public Sub Main()
        Dim employee1 As Employee = New Employee
        employee1.MonthlySalary = 1000
        Console.WriteLine(employee1.GetYearlySalary())
        '
        Dim manager1 As Manager = New Manager
        manager1.MonthlySalary = 2000
        manager1.Bonus = 10000
        Console.WriteLine(manager1.GetYearlySalary())
        '
        Console.ReadLine()
    End Sub
End Module
Console Application Output
12000
34000
Opgave 2 :
Creëer de nodige klasse om met onderstaande clientcode onderstaand programmaverloop te bekomen.
Visual Basic 2012 Broncode - Codevoorbeeld 292
Module Exercise2Task
    Sub Main()
        Dim addition1 As Addition = New Addition(3, 4)
        Console.WriteLine(addition1.GetSum())
        Console.WriteLine(addition1.ToString())
        '
        addition1.Operand1 = 5
        addition1.Operand2 = 6
        Console.WriteLine(addition1.GetSum())
        Console.WriteLine(addition1.ToString())
        '
        Console.ReadLine()
    End Sub
End Module
Console Application Output
7
3 + 4 = 7
11
5 + 6 = 11
Oplossing 2 :
Visual Basic 2012 Broncode - Codevoorbeeld 293
Class Addition
    Public Sub New(ByVal operand1 As Integer, ByVal operand2 As Integer)
        Me.Operand1 = operand1
        Me.Operand2 = operand2
    End Sub
    Public Property Operand1 As Integer
    Public Property Operand2 As Integer
    Public Function GetSum() As Integer
        GetSum = Operand1 + Operand2
    End Function
    Public Overrides Function ToString() As String
        ToString = Operand1 & " + " & Operand2 & " = " & GetSum()
    End Function
End Class
Opgave 3 :
Creëer de nodige klassen om met onderstaande clientcode onderstaande programmaverloop te bekomen.
Visual Basic 2012 Broncode - Codevoorbeeld 294
Module Exercise3Task
    Sub Main()
        Dim airport1 As Airport = New Airport("ZAV", "Brussels")
        Dim airport2 As Airport = New Airport("NYK", "New York Kennedy")
        '
        Dim flight1 As Flight = New Flight(airport1, airport2)
        Dim flight2 As Flight = New Flight(airport2, airport1)
        '
        Dim holiday1 As Holiday = New Holiday
        holiday1.Add(flight1)
        holiday1.Add(flight2)
        '
        For index As Integer = 0 To holiday1.Count - 1
            Console.WriteLine(holiday1.Item(index).ToString())
        Next
        '
        Console.ReadLine()
    End Sub
End Module
Console Application Output
ZAV : Brussels -> NYK : New York Kennedy
NYK : New York Kennedy -> ZAV : Brussels
Oplossing 3 :
Visual Basic 2012 Broncode - Codevoorbeeld 295
Class Holiday
    Private _Items As Flight()
    Private _Count As Integer
    Public ReadOnly Property Count() As Integer
        Get
            Count = _Count
        End Get
    End Property
    Public Sub Add(ByVal flight As Flight)
        ReDim Preserve _Items(Count)
        _Items(Count) = flight
        _Count += 1
    End Sub
    Default Public ReadOnly Property Item(ByVal index As Integer) As Flight
        Get
            Item = _Items(index)
        End Get
    End Property
End Class
Class Flight
    Public Sub New(ByVal departure As Airport, ByVal arrival As Airport)
        Me.Departure = departure
        Me.Arrival = arrival
    End Sub
    Public Property Departure As Airport
    Public Property Arrival As Airport
    Public Overrides Function ToString() As String
        ToString = Departure.ToString() & " -> " & Arrival.ToString()
    End Function
End Class
Class Airport
    Public Sub New(ByVal code As String, ByVal Name As String)
        Me.Code = code
        Me.Name = Name
    End Sub
    Public Property Code As String
    Public Property Name As String
    Public Overrides Function ToString() As String
        ToString = Code & " : " & Name
    End Function
End Class

Dit artikel is gepubliceerd op maandag 15 oktober 2012 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.