|
Dit artikel is gepubliceerd op woensdag 28 april 2010 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
9.13.1. Overridable en OverridesWanneer 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 Broncode 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())
Dim object2 As Class2 = New Class2
Console.WriteLine(object2.Method1())
Console.ReadLine()
End Sub
End ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic 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.
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. Terug naar boven 9.13.2. NotOverridableEen 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 Broncode 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
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 ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic 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 Broncode Class Counter
Protected m_Value As Integer
Public ReadOnly Property Value() As Integer
Get
Value = m_Value
End Get
End Property
Public Overridable Sub Raise()
m_Value += 1
End Sub
Public Overridable Sub Lower()
m_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 ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic 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 Broncode Class SpecialCounter : Inherits Counter
Private m_StepValue As Integer = 1
Public Property StepValue() As Integer
Get
StepValue = m_StepValue
End Get
Set(ByVal value As Integer)
m_StepValue = value
End Set
End Property
Public Overrides Sub Raise()
m_Value += StepValue
End Sub
Public Overrides Sub Lower()
m_Value -= StepValue
End Sub
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
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 m_Value ( de toestand Value ) aanpassen, is het ook logisch de velden ( hier veld m_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 Broncode 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 ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output 0
5
10
5 Terug naar boven
9.13.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.
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 Broncode Class Person
Public Sub New(ByVal name As String)
Me.Name = name
End Sub
Private m_Name As String
Public Property Name() As String
Get
Name = m_Name
End Get
Set(ByVal value As String)
m_Name = value
End Set
End Property
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
Private m_ClassGroup As String
Public Property ClassGroup() As String
Get
ClassGroup = m_ClassGroup
End Get
Set(ByVal value As String)
m_ClassGroup = value
End Set
End Property
Public Overrides Function ToString() As String
ToString = Name & " (" & ClassGroup & ")"
End Function
End Class
Module Example5
Public Sub Main()
Dim person1 As Person = New Person("John")
Console.WriteLine(person1.ToString())
Dim student1 As Student = New Student("Jane", "Visual Basic")
Console.WriteLine(student1.ToString())
Console.ReadLine()
End Sub
End ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output (*).Person
Jane (Visual Basic) (*) Hier staat de na(a)m(en) van de namespace(s) waarin de klasse Person is gedefinieerd. Terug naar boven
9.13.4. MyBaseRegelmatig 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 Broncode 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()
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 ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic 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. Terug naar boven
9.13.5. OefeningenOpgave 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 Broncode Class Employee
Private m_MonthlySalary As Decimal
Public Property MonthlySalary() As Decimal
Get
MonthlySalary = m_MonthlySalary
End Get
Set(ByVal value As Decimal)
m_MonthlySalary = value
End Set
End Property
Public Overridable Function GetYearlySalary() As Decimal
GetYearlySalary = MonthlySalary * 12
End Function
End Class
Class Manager : Inherits Employee
Private m_Bonus As Decimal
Public Property Bonus() As Decimal
Get
Bonus = m_Bonus
End Get
Set(ByVal value As Decimal)
m_Bonus = value
End Set
End Property
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 ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output 12000
34000 Opgave 2 : Creëer de nodige klasse om met onderstaande clientcode onderstaand programmaverloop te bekomen. Visual Basic Broncode 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 ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output 7
3 + 4 = 7
11
5 + 6 = 11 Oplossing 2 : Visual Basic Broncode Class Addition
Public Sub New(ByVal operand1 As Integer, ByVal operand2 As Integer)
Me.Operand1 = operand1
Me.Operand2 = operand2
End Sub
Private m_Operand1 As Integer
Public Property Operand1() As Integer
Get
Operand1 = m_Operand1
End Get
Set(ByVal value As Integer)
m_Operand1 = value
End Set
End Property
Private m_Operand2 As Integer
Public Property Operand2() As Integer
Get
Operand2 = m_Operand2
End Get
Set(ByVal value As Integer)
m_Operand2 = value
End Set
End Property
Public Function GetSum() As Integer
GetSum = Operand1 + Operand2
End Function
Public Overrides Function ToString() As String
ToString = Operand1 & " + " & Operand2 & " = " & GetSum()
End Function
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Opgave 3 : Creëer de nodige klassen om met onderstaande clientcode onderstaande programmaverloop te bekomen. Visual Basic Broncode 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 ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output ZAV : Brussels -> NYK : New York Kennedy
NYK : New York Kennedy -> ZAV : Brussels Oplossing 3 : Visual Basic Broncode Class Holiday
Private m_Items As Flight()
Private m_Count As Integer
Public ReadOnly Property Count() As Integer
Get
Count = m_Count
End Get
End Property
Public Sub Add(ByVal flight As Flight)
ReDim Preserve m_Items(Count)
m_Items(Count) = flight
m_Count += 1
End Sub
Default Public ReadOnly Property Item(ByVal index As Integer) As Flight
Get
Item = m_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
Private m_Departure As Airport
Public Property Departure() As Airport
Get
Departure = m_Departure
End Get
Set(ByVal value As Airport)
m_Departure = value
End Set
End Property
Private m_Arrival As Airport
Public Property Arrival() As Airport
Get
Arrival = m_Arrival
End Get
Set(ByVal value As Airport)
m_Arrival = value
End Set
End Property
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
Private m_Code As String
Public Property Code() As String
Get
Code = m_Code
End Get
Set(ByVal value As String)
m_Code = value
End Set
End Property
Private m_Name As String
Public Property Name() As String
Get
Name = m_Name
End Get
Set(ByVal value As String)
m_Name = value
End Set
End Property
Public Overrides Function ToString() As String
ToString = Code & " : " & Name
End Function
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Dit artikel is gepubliceerd op woensdag 28 april 2010 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
Visual Basic 2008 & 2010 Boeken
Berichten
|