|
Dit artikel is gepubliceerd op woensdag 28 april 2010 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
11.5.1. Redefinition - Overridable en OverridesDe compiler zal beslissen op basis van het statisch type van de ontvangerexpressie welke member wordt aangeroepen. At runtime bepaalt het dynamisch type van de ontvangerexpressie aan welke implementatie deze call gebonden wordt. Visual Basic Broncode Namespace Redefinition
Class Class1
Public Overridable Sub Method1()
Console.WriteLine("Class1.Method1()")
End Sub
End Class
Class Class2 : Inherits Class1
Public Overrides Sub Method1()
Console.WriteLine("Class2.Method1()")
End Sub
End Class
Class Class3 : Inherits Class2
Public Overrides Sub Method1()
Console.WriteLine("Class3.Method1()")
End Sub
End Class
Class Example
Public Shared Sub Main()
Dim object1_1 As Class1 = New Class1
Dim object1_2 As Class1 = New Class2
Dim object1_3 As Class1 = New Class3
Dim object2_2 As Class2 = New Class2
Dim object2_3 As Class2 = New Class3
Dim object3_3 As Class3 = New Class3
object1_1.Method1()
object1_2.Method1()
object1_3.Method1()
object2_2.Method1()
object2_3.Method1()
object3_3.Method1()
Console.ReadLine()
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output Class1.Method1()
Class2.Method1()
Class3.Method1()
Class2.Method1()
Class3.Method1()
Class3.Method1() Terug naar boven 11.5.2. Shadowing - ShadowsIets wat vaak verward wordt met redefinition is "shadowing", toch heeft dit een totaal ander effect.
De overschaduwende member ( hier Method1 uit Class2 ), die wordt gemarkeerd met het Shadows keyword, is een nieuwe member die wordt toegevoegd in een afgeleide klasse, hier toegevoegd in Class2. Deze nieuwe member heeft dezelfde naam als de overschaduwde member.
Door shadowing toe te passen worden verdere herdefinities van de overschaduwde member ( hier Method1 uit Class1 ) - vanaf de klasse die deze overschaduwende member introduceert ( Class2 ) - verhinderd. Visual Basic Broncode Namespace Shadowing
Class Class1
Public Overridable Sub Method1()
Console.WriteLine("Class1.Method1()")
End Sub
End Class
Class Class2 : Inherits Class1
Public Overridable Shadows Sub Method1()
Console.WriteLine("Class2.Method1()")
End Sub
End Class
Class Class3 : Inherits Class2
Public Overrides Sub Method1()
Console.WriteLine("Class3.Method1()")
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Er is hier sprake van twee verschillende members met de naam Method1.
De eerste gedefinieerd in Class1 bevat implementatie (1) en wordt overgeërfd in Class2 en Class3. Class2 en Class3 erven dan ook implementatie (1) over.
De tweede Method1 is gedefinieerd vanaf Class2 en bevat implementatie (2), deze wordt overgeërfd en geherdefinieerd in Class3 met implementatie (3). Een nieuwe member wordt in Class2 geïntroduceerd, deze nieuwe member heeft dezelfde naam heeft als een overgeërfde member. Naast de gemeenschappelijke identifier hebben deze twee verschillende Method1 members niets met elkaar te maken. Het is echter wel zo dat vanaf Class2 de eerste Method1 niet meer kan worden geherdefinieerd.
De compiler zal op basis van het statisch type van de ontvangerexpressie bepalen welke Method1 wordt aangeroepen. Hiervoor verkiest hij de meest recent gedefinieerde Method1.
Op ontvangerexpressie van statisch type Class1 kan men slechts één Method1 ( de eerste ) worden aangeroepen. Wanneer Method1 op ontvangerexpressies van statisch types Class2 of Class3 wordt aangeroepen dan beschouwd de compiler dit als een call naar de tweede Method1. Visual Basic Broncode Namespace Shadowing
Class Example
Public Shared Sub Main()
Dim object1_1 As Class1 = New Class1
Dim object1_2 As Class1 = New Class2
Dim object1_3 As Class1 = New Class3
Dim object2_2 As Class2 = New Class2
Dim object2_3 As Class2 = New Class3
Dim object3_3 As Class3 = New Class3
object1_1.Method1()
object1_2.Method1()
object1_3.Method1()
object2_2.Method1()
object2_3.Method1()
object3_3.Method1()
Console.ReadLine()
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output Class1.Method1()
Class1.Method1()
Class1.Method1()
Class2.Method1()
Class3.Method1()
Class3.Method1() De regels omtrent shadowing zijn ingewikkeld en vaak verschillend. De verschillende talen gebruiken verschillende variaties van shadowing, naast "shadowing by name" beschikken sommige talen ook over de mogelijkheid om "shadowing by signature" toe te passen. Dit in tegenstelling tot bijvoorbeeld overloading of redefinition. In bijna alle talen zijn de regels omtrent deze gelijk, dit is niet het geval bij shadowing.
In Visual Basic is zowel shadowing by name als by signature mogelijk.
Het gebruik van shadowing veroorzaakt moeilijk leesbare code, hierdoor raadt men doorgaans aan enkel shadowing te gebruiken indien noodzakelijk. Terug naar boven
11.5.3. Fragile Base Class ProblemIndien een basisklasse - waarvan je niet de eigenaar bent - opeens een member introduceert met dezelfde identifier als een member uit je eigen gespecialiseerde klasse, kan het nuttig zijn shadowing toe te passen. Wat voor effect bovenstaande situatie zou hebben, is afhankelijk van de gebruikte taal. Sommige talen zouden fouten geven, ander talen zouden je eigen member ( uit de gespecialiseerde klasse ) als een overschrijvende member beschouwen. Indien er echter geen verband is tussen de member uit de basis- en afgeleide klasse, is shadowing meer toepasselijk dan redefinition. Visual Basic zal in bovenvermelde situatie automatisch schadowing gebruiken.
Basisklassen zijn fragiele dingen, als je er wijzingen aan aanbrengt kan dit grote gevolgen hebben voor de afgeleiden.
Veronderstel onderstaande CharString. Visual Basic Broncode Namespace FragileBaseClass1
Class CharString
Private m_Items As Char() = {}
Public Overridable Sub Add(ByVal aChar As Char)
ReDim Preserve m_Items(m_Items.Length)
m_Items(m_Items.Length - 1) = aChar
End Sub
Public Overridable Sub AddAll(ByVal chars As Char())
For Each charElement As Char In chars
Add(charElement)
Next
End Sub
Public Overrides Function ToString() As String
If m_Items IsNot Nothing Then
For Each charElement As Char In m_Items
ToString &= charElement
Next
End If
End Function
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
In de abstractie ( hier in de publieke interface ) van de klasse CharString is niet voorzien om in clients het aantal elementen ( aantal Chars ) op te vragen. Als we deze mogelijkheid toch willen toevoegen, zonder de basisklasse aan te passen ( omdat we dit niet kunnen ( bijvoorbeeld niet beschikken over de sourcecode ) of niet wensen ), kunnen we hiervoor een afgeleide klasse creëren. Visual Basic Broncode Namespace FragileBaseClass1
Class CountedCharString : Inherits CharString
Private m_Count As Integer
Public Overrides Sub Add(ByVal aChar As Char)
MyBase.Add(aChar)
m_Count += 1
End Sub
Public ReadOnly Property Count() As Integer
Get
Count = m_Count
End Get
End Property
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Bovenstaande klasse biedt nu de gewenste mogelijkheid, om het aantal characters uit het CharString object op te vragen. Visual Basic Broncode Namespace FragileBaseClass1
Class Example
Public Shared Sub Main()
Dim countedCharString1 As New CountedCharString
countedCharString1.Add("a"c)
countedCharString1.Add("b"c)
countedCharString1.AddAll(New Char() {"c"c, "d"c})
Console.WriteLine(countedCharString1.ToString())
Console.WriteLine(countedCharString1.Count)
Console.ReadLine()
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output abcd
4 De expressie countedCharString1.Count levert 4 op.
Toch is bovenstaande geherdefinieerde implementatie van de Add method in de CountedCharString klasse een riskante onderneming. De opgeleverde Count waarde is hier afhankelijk van het aantal keer de Add method wordt aangeroepen. Enkel doordat de AddAll method de Add method gebruikt, functioneert dit correct.
Stel in de basisklasse wordt de minder efficiënte AddAll implementatie vervangen door een efficiënter implementatie. Visual Basic Broncode Namespace FragileBaseClass2
Class CharString
Private m_Items As Char() = {}
Public Overridable Sub Add(ByVal aChar As Char)
ReDim Preserve m_Items(m_Items.Length)
m_Items(m_Items.Length - 1) = aChar
End Sub
Public Overridable Sub AddAll(ByVal chars As Char())
Dim oldUpperBound, newUpperBound As Integer
If m_Items IsNot Nothing Then oldUpperBound = m_Items.Length - 1
If chars IsNot Nothing Then newUpperBound = _
oldUpperBound + chars.Length
ReDim Preserve m_Items(newUpperBound)
Dim index As Integer = oldUpperBound + 1
For Each charElement As Char In chars
m_Items(index) = charElement
index += 1
Next
End Sub
Public Overrides Function ToString() As String
If m_Items IsNot Nothing Then
For Each charElement As Char In m_Items
ToString &= charElement
Next
End If
End Function
End Class
Class CountedCharString : Inherits CharString
Private m_Count As Integer
Public Overrides Sub Add(ByVal aChar As Char)
MyBase.Add(aChar)
m_Count += 1
End Sub
Public ReadOnly Property Count() As Integer
Get
Count = m_Count
End Get
End Property
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Dan zal dezelfde client zal voor de expressie countedCharString1.Count twee opleveren. Visual Basic Broncode Namespace FragileBaseClass2
Class Example
Public Shared Sub Main()
Dim countedCharString1 As New CountedCharString
countedCharString1.Add("a"c)
countedCharString1.Add("b"c)
countedCharString1.AddAll(New Char() {"c"c, "d"c})
Console.WriteLine(countedCharString1.ToString())
Console.WriteLine(countedCharString1.Count)
Console.ReadLine()
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output abcd
2 Wat duidelijk niet correct is.
Het probleem zou hier op te lossen zijn door ook de AddAll method in de afgeleide klasse te herdefiniëren. Terug naar boven
11.5.4. Overloading, Redefinition of ShadowingStel dat zowel Class1 als Class2 ( die overerft van Class1 ) een member met de signatuur Public Sub Test() definiëren. Visual Basic Broncode Namespace OverloadingRedefinitionOrShadowing1
Class Class1
Public Sub Test()
Console.WriteLine("Class1.Test()")
End Sub
End Class
Class Class2 : Inherits Class1
Public Sub Test()
Console.WriteLine("Class2.Test()")
End Sub
End Class
Class Example
Public Shared Sub Main()
Dim object1_1 As Class1 = New Class1
object1_1.Test()
Dim object1_2 As Class1 = New Class2
object1_2.Test()
Dim object2 As Class2 = New Class2
object2.Test()
Console.ReadLine()
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output Class1.Test()
Class1.Test()
Class2.Test() Dan zie je hoe shadowing wordt toegepast, ondanks dat we dit niet expliciet hebben opgegeven ( geen gebruik van het keyword Shadows ).
De compiler geeft wel een warning dat shadowing zal worden gebruikt.
Stel dat Class1 een Public Overridable Sub Test() definieert en afgeleide Class2 hier een Public Sub Test() aan toevoegt. Visual Basic Broncode Namespace OverloadingRedefinitionOrShadowing2
Class Class1
Public Overridable Sub Test()
Console.WriteLine("Class1.Test()")
End Sub
End Class
Class Class2 : Inherits Class1
Public Sub Test()
Console.WriteLine("Class2.Test()")
End Sub
End Class
Class Example
Public Shared Sub Main()
Dim object1_1 As Class1 = New Class1
object1_1.Test()
Dim object1_2 As Class1 = New Class2
object1_2.Test()
Dim object2 As Class2 = New Class2
object2.Test()
Console.ReadLine()
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output Class1.Test()
Class1.Test()
Class2.Test() Ook hier zal shadowing worden toegepast zonder dat we dit expliciet aangeven.
We krijgen opnieuw een warning die ons waarschuwt dat shadowing zal worden toegepast.
Stel basisklasse Class1 met een Public Overridable Sub Test() waarvan afgeleide klasse een Public Overrides Sub Test() toevoegt. Visual Basic Broncode Namespace OverloadingRedefinitionOrShadowing3
Class Class1
Public Overridable Sub Test()
Console.WriteLine("Class1.Test()")
End Sub
End Class
Class Class2 : Inherits Class1
Public Overrides Sub Test()
Console.WriteLine("Class2.Test()")
End Sub
End Class
Class Example10
Public Shared Sub Main()
Dim object1_1 As Class1 = New Class1
object1_1.Test()
Dim object1_2 As Class1 = New Class2
object1_2.Test()
Dim object2 As Class2 = New Class2
object2.Test()
Console.ReadLine()
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output Class1.Test()
Class2.Test()
Class2.Test() Bovenstaand voorbeeld maakt op correcte wijze gebruik van redefinition.
Stel klasse Class1 met Public Sub Test() en een afgeleide klasse Class2 met een Public Shadows Sub Test(). Visual Basic Broncode Namespace OverloadingRedefinitionOrShadowing4
Class Class1
Public Sub Test()
Console.WriteLine("Class1.Test()")
End Sub
End Class
Class Class2 : Inherits Class1
Public Shadows Sub Test()
Console.WriteLine("Class2.Test()")
End Sub
End Class
Class Example11
Public Shared Sub Main()
Dim object1_1 As Class1 = New Class1
object1_1.Test()
Dim object1_2 As Class1 = New Class2
object1_2.Test()
Dim object2 As Class2 = New Class2
object2.Test()
Console.ReadLine()
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output Class1.Test()
Class1.Test()
Class2.Test() Bovenstaand voorbeeld maakt op gebruik van shadowing, hier wordt dit ook expliciet aangegeven via het keyword Shadows.
Stel klasse Class1 met Public Sub Test() en afgeleide klasse Class2 met een Public Overloads Sub Test(). Visual Basic Broncode Namespace OverloadingRedefinitionOrShadowing5
Class Class1
Public Sub Test()
Console.WriteLine("Class1.Test()")
End Sub
End Class
Class Class2 : Inherits Class1
Public Overloads Sub Test()
Console.WriteLine("Class2.Test()")
End Sub
End Class
Class Example12
Public Shared Sub Main()
Dim object1_1 As Class1 = New Class1
object1_1.Test()
Dim object1_2 As Class1 = New Class2
object1_2.Test()
Dim object2 As Class2 = New Class2
object2.Test()
Console.ReadLine()
End Sub
End Class
End NamespaceDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output Class1.Test()
Class1.Test()
Class2.Test() In klasse Class2 wordt gesuggereerd dat overloading wordt gebruikt, maar er zijn geen verschillen aangebracht in de parameters ( wat vereist is volgens de overload resolution ). Dit is een foutieve toepassing van overloading.
Hier zal shadowing worden gebruikt, ondanks het keyword Overloads, bemerk dat de compiler ons hier geen waarschuwing voor geeft.
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
|