|
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
9.15.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 2010 Broncode Class Class1 Public Overridable Function Method1() As String Method1 = "Class1.Method1()" End FunctionEnd ClassClass Class2 : Inherits Class1 Public Overrides Function Method1() As String Method1 = "Class2.Method1()" End FunctionEnd ClassModule 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 SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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.
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. boven
9.15.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 2010 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 FunctionEnd ClassClass 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 FunctionEnd ClassClass Class5 : Inherits Class4 Public Overrides Function Method1() As String Method1 = "Class5.Method1()" End FunctionEnd ClassModule 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 SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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 2010 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 SubEnd ClassModule 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 SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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 2010 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 SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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 2010 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 SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output 0
5
10
5 boven
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.
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 2010 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 PropertyEnd ClassClass 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 FunctionEnd ClassModule 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 SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output (*).Person
Jane (Visual Basic) (*) Hier staat de na(a)m(en) van de namespace(s) waarin de klasse Person is gedefinieerd. boven
9.15.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 2010 Broncode Partial Class Counter Public Overrides Function ToString() As String ToString = Value.ToString() End FunctionEnd ClassPartial Class SpecialCounter Public Overrides Function ToString() As String ToString = MyBase.ToString() & " - Step : " & StepValue.ToString() End FunctionEnd ClassModule 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 SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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. boven
9.15.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 2010 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 FunctionEnd ClassClass 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 FunctionEnd ClassModule 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 SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output 12000
34000 Opgave 2 : Creëer de nodige klasse om met onderstaande clientcode onderstaand programmaverloop te bekomen. Visual Basic 2010 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 SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output 7
3 + 4 = 7
11
5 + 6 = 11 Oplossing 2 : Visual Basic 2010 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 FunctionEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Opgave 3 : Creëer de nodige klassen om met onderstaande clientcode onderstaande programmaverloop te bekomen. Visual Basic 2010 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 SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output ZAV : Brussels -> NYK : New York Kennedy
NYK : New York Kennedy -> ZAV : Brussels Oplossing 3 : Visual Basic 2010 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 PropertyEnd ClassClass 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 FunctionEnd ClassClass 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 FunctionEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
|