|
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
20.3.1. MustOverrideNiet alleen een klasse zelf kunnen we abstract maken, ook members kunnen abstract worden gemaakt. Deze abstracte members hebben een signatuur ( zijn aanwezig in een klasse met een bepaalde interface ), maar hebben geen implementatie.
Uiteraard kunnen we dergelijke members enkel in een abstracte klasse definiëren, want anders zouden we voor objecten van concrete types die members kunnen aanroepen, zonder dat geweten is welke implementatie aan die aanroep moet gekoppeld worden ( welke binding moet worden gebruikt ).
Een member maak je abstract via het keyword MustOverride, en de definitie hiervan bestaat enkel uit de signatuurregel. Een concreet afgeleide klasse is dan verplicht een Overrides implementatie te gaan binden aan die memberinterface die hij van die abstracte klasse heeft overgeërfd.
Alle figuren in ons systeem ( alle afgeleide types van Figure ) zouden bijvoorbeeld nut hebben aan een member die de oppervlakte ( GetArea() ) oplevert. Gezien deze member voor alle soorten van figuren van toepassing is, kunnen we deze member best in het generalisatietype Figure opnemen, zo kan de member worden overgenomen naar alle gespecialiseerde afgeleide types. We kunnen echter moeilijk een implementatie koppelen aan die member omdat er simpelweg geen algemene formule bestaat voor het bepalen van de oppervlakte die voor alle gespecialiseerde soorten figuren van toepassing is. Dit is geen probleem we kunnen die member als abstracte member ( MustOverride member ) opnemen in het generalisatietype Figure, alle concrete afgeleide types kunnen/moeten daarvoor dan een implementatie voorzien ( Overrides implementatie ). Visual Basic 2010 Broncode MustInherit Class Figure Private m_Color As String Public Property Color() As String Get Color = m_Color End Get Set( ByVal value As String) m_Color = value End Set End Property Protected Sub New( ByVal color As String) Me.Color = color End Sub Public MustOverride Function GetArea() As Double End ClassClass Rectangle : Inherits Figure Private m_Height As Double Public Property Height() As Double Get Height = m_Height End Get Set( ByVal value As Double) m_Height = value End Set End Property Private m_Width As Double Public Property Width() As Double Get Width = m_Width End Get Set( ByVal value As Double) m_Width = value End Set End Property Public Sub New( ByVal color As String, _ ByVal height As Double, ByVal width As Double) MyBase.New(color) Me.Height = height Me.Width = width End Sub Public Overrides Function GetArea() As Double GetArea = Height * Width End FunctionEnd ClassClass Circle : Inherits Figure Private m_Radius As Double Public Property Radius() As Double Get Radius = m_Radius End Get Set( ByVal value As Double) m_Radius = value End Set End Property Public Sub New( ByVal color As String, _ ByVal radius As Double) MyBase.New(color) Me.Radius = radius End Sub Public Overrides Function GetArea() As Double GetArea = Radius ^ 2 * System.Math.PI End FunctionEnd ClassClass Example1 Public Shared Sub Main() Dim rectangle1 As Rectangle = New Rectangle( "red", 10, 20) Console.WriteLine(rectangle1.GetArea()) Dim circle1 As Circle = New Circle( "yellow", 10) Console.WriteLine(circle1.GetArea()) Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output 200
314,159265358979 De abstracte member (1) wordt dus gedefinieerd door het MustOverride keyword, en bestaat dus enkel uit de signatuur van die member. Public is hier opgenomen in de signatuur, omdat we wensen dat Area ook beschikbaar is in de publieke interface van die afgeleide types, en clients dus op die gespecialiseerde Figure objecten die member kunnen aanroepen.
Enkel implementatiemembers ( methods en properties ) kunnen als MustOverride worden gedefinieerd. De herdefinitie ( bijhorende Overrides ) moet voorzien in een nieuwe implementatie voor die member. Een member zonder implementatie ( zoals een field ) kan ook moeilijk gebonden worden aan een nieuwe implementatie.
Private members kunnen ook niet als MustOverride worden gemarkeerd. Gezien er geen interface naar die member ( aanwezigheid van die member in de interface ) wordt overgeërfd, kan deze niet overgenomen interface niet geherdefinieerd worden.
Enkel concrete afgeleide klassen moeten een implementatie voorzien voor de overgeërfde abstracte member. Is de afgeleide klasse zelf abstract dan kan (1), maar hoeft deze klasse geen implementatie te voorzien (2). Visual Basic 2010 Broncode MustInherit Class Class1 MustOverride Sub Method1() End ClassMustInherit Class Class2 : Inherits Class1 End ClassClass Class3 : Inherits Class2 Public Overrides Sub Method1() Console.WriteLine( "Class3.Method1()") End SubEnd ClassClass Class4 : Inherits Class3End ClassMustInherit Class Class5 : Inherits Class1 Public Overrides Sub Method1() Console.WriteLine( "Class5.Method1()") End SubEnd ClassClass Class6 : Inherits Class5End ClassClass Example2 Public Shared Sub Main() Dim object3 As Class3 = New Class3 object3.Method1() Dim object4 As Class4 = New Class4 object4.Method1() Dim object6 As Class6 = New Class6 object6.Method1() Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output Class3.Method1()
Class3.Method1()
Class5.Method1() Dat abstracte klassen die een abstracte member overerven geen implementatie moeten voorzien voor die member is niet zo vreemd. Van dat afgeleide type zelf kan immers toch geen object worden aangemaakt waarop die members zou worden aangeroepen en waaraan dus een implementatie zou gekoppeld worden.
Dat concrete afgeleide klassen die een abstracte member overerven wel een implementatie moeten voorzien is ook logisch, want hiervan kunnen wel objecten worden aangemaakt waarop die member kan worden aangeroepen en waaraan dus wel een implementatie zou moeten worden gekoppeld. Visual Basic 2010 Broncode Class Example3 Public Shared Sub Main() Dim figure1 As Figure = New Rectangle( "red", 10, 20) Console.WriteLine(figure1.GetArea()) Console.WriteLine(figure1.Color) Console.WriteLine() Dim figure2 As Figure = New Circle( "yellow", 10) Console.WriteLine(figure2.GetArea()) Console.WriteLine(figure2.Color) Console.WriteLine() Dim figures As Figure() = _ New Figure() {figure1, figure2, New Circle( "red", 100)} For Each figure As Figure In figures Console.WriteLine(figure.GetArea()) Console.WriteLine(figure.Color) Console.WriteLine() Next Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output 200
red
314,159265358979
yellow
200
red
314,159265358979
yellow
31415,9265358979
red Bovenstaande client verduidelijkt nogmaals dat we in een variabele gedeclareerd van een basis type ( Figure ) een referentie kunnen stockeren van een object van een afgeleid type ( Rectangle of Circle ).
Het is dus niet omdat het een abstract type is, dat je er geen variabele van zou kunnen declareren, enkel dergelijk object ( van abstract type ) instantiëren kan niet.
De array figures gedeclareerd met elementen van het type Figure kan referenties bevatten van Rectangle en Circle objecten. Maar op de figure expressie gedeclareerd van het type Figure en gebruikt in de For Each ... Next kan men dan enkel de members aanroepen die gedefinieerd zijn in het statisch type van die expressie ( Figure ). Dus enkel de members GetArea() en Color zijn beschikbaar, de gespecialiseerde Height, Width en Radius members zijn pas beschikbaar indien casting wordt toegepast. boven
20.3.2. OefeningOpgave :
Gegeven zijn onderstaande ( correcte ) klassen en hun members : Visual Basic 2010 Broncode MustInherit Class Class_1 Public MustOverride Sub Command1() Public Overridable Sub Command2() Console.WriteLine( "Class_1.Command2()") End SubEnd ClassClass Class_2 : Inherits Class_1 Public Overrides Sub Command1() Console.WriteLine( "Class_2.Command1()") End Sub Public Overridable Sub Command3() Console.WriteLine( "Class_2.Command3()") End Sub Public Overridable Sub Command4() Console.WriteLine( "Class_2.Command4()") End SubEnd ClassMustInherit Class Class_3 : Inherits Class_1 Public MustOverride Sub Command4() Public Overridable Sub Command5() Console.WriteLine( "Class_3.Command5()") End SubEnd ClassMustInherit Class Class_4 : Inherits Class_3 Public Overrides Sub Command1() Console.WriteLine( "Class_4.Command1()") End Sub Public Overrides Sub Command2() Console.WriteLine( "Class_4.Command2()") End Sub Public Overridable Sub Command6() Console.WriteLine( "Class_4.Command6()") End SubEnd ClassClass Class_5 : Inherits Class_4 Public Overrides Sub Command4() Console.WriteLine( "Class_5.Command4()") End Sub Public Overrides Sub Command5() Console.WriteLine( "Class_5.Command5()") End Sub Public Overridable Sub Command7() Console.WriteLine( "Class_5.Command7()") End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Gegeven zijn onderstaande ( deels foutieve ) klasse en zijn members.
Onderzoek de implementaties van onderstaande boodschappen Query1(), Query2() en Query3() en leg uit wat er verkeerd aan is. Visual Basic 2010 Broncode Class Class_6 End ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Voor verder onderzoek veronderstellen we dat de foutieve members uit bovenstaande klasse zijn verwijderd.
Onderzoek de uitvoer of wat fout loopt bij elk van onderstaande regels. Ga na of er fouten zullen optreden, welke deze zijn, en ga na welke de uitvoer zou zijn ( indien geen fouten ). Visual Basic 2010 Broncode Class Exercise1Task Public Shared Sub Main() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Oplossing : Visual Basic 2010 Broncode Class Class_6 Public Function Query3() As Class_1 Query3 = New Class_5 End Function Public Sub Command1( ByVal parameter As Class_3) parameter.Command4() End Sub Public Sub Command2( ByVal parameter As Class_1) parameter.Command2() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
- Query1() is foutief, Class_3 is abstract en kan niet geïnstantieerd worden (1). - Query2() is foutief, Class_5 is niet afgeleid van Class_2 (2). - Query3() is correct. Visual Basic 2010 Broncode Class Exercise1Solution Public Shared Sub Main() Dim object1 As Class_1 = New Class_5 object1.Command1() object1.Command2() Dim object2 As Class_2 = New Class_2 object2.Command1() object2.Command2() object2.Command3() object2.Command4() Dim object3 As Class_3 = New Class_5 object3.Command1() object3.Command2() object3.Command4() object3.Command5() Dim object4 As Class_5 = New Class_5 object4.Command1() object4.Command2() object4.Command4() object4.Command5() object4.Command6() object4.Command7() Dim object5 As Class_6 = New Class_6 object5.Command1(object3) object5.Command1(object4) object5.Command2(object1) object5.Command2(object2) object5.Command2(object3) object5.Command2(object4) object5.Query3().Command1() object5.Query3().Command2() Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output Class_4.Command1()
Class_4.Command2()
Class_2.Command1()
Class_1.Command2()
Class_2.Command3()
Class_2.Command4()
Class_4.Command1()
Class_4.Command2()
Class_5.Command4()
Class_5.Command5()
Class_4.Command1()
Class_4.Command2()
Class_5.Command4()
Class_5.Command5()
Class_4.Command6()
Class_5.Command7()
Class_5.Command4()
Class_5.Command4()
Class_4.Command2()
Class_1.Command2()
Class_4.Command2()
Class_4.Command2()
Class_4.Command1()
Class_4.Command2()
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
|