|
Dit artikel is gepubliceerd op woensdag 28 april 2010 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
In de client tot nu toe hebben we bijna steeds meteen na het instantiëren van een object eigenschapswaarden ingesteld voor dat object. Dit is vrij logisch, want met een "leeg" object zijn we immers meestal niet veel. Met "leeg" wordt hier bedoeld : zonder object-specifieke toestand, zonder specifieke waarden ( andere dan de initiële ) voor die instantie.
Om af te dwingen dat bij het aanmaken van een instantie voor bepaalde eigenschappen van deze instantie initiële waardes worden voorzien kan men gebruik maken van constructoren. Dit zijn steeds procedures met de identifier New. Deze constructoren worden impliciet aangeroepen bij het gebruik van een object initializer ( keyword New gevolgd door de identifier van de klasse die men wil instantiëren ).
Men kan in de constructor argumentvariabelen definiëren, waardoor het mogelijk wordt bij het instantiëren ( in de objectinitializer ) de nodige argumentwaarden door te geven.
Hieronder een voorbeeld van een klasse Person met een constructor (1) die toelaat een initiële Name-eigenschapswaarde op te geven in de object initializer. 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
Module Client1
Sub Main()
Dim person1 As Person = New Person("John")
Console.WriteLine(person1.Name)
Console.ReadLine()
End Sub
End ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
De client MOET hier (2) nu meteen bij het construeren van het object ( van het type Person ) een initiële Name waarde opgeven. De doorgegeven argumentwaarde ( name ) wordt vervolgens toegekend aan de eigenschap ( Me.Name ). Dit vereenvoudigd natuurlijk sterk de client-code.
Ook clients ( of clientprogrammeurs ) kunnen de naam van argumentvariabelen zien. Bedenk maar hoe bijvoorbeeld in de Visual Studio IDE er een "tooltip" komt met informatie over de verwachte te doorgegeven argumentwaarden als je een method aanroept. In deze informatie staat ook de identifier van de argumentvariabelen vermeldt. Een clientprogrammeur kan steeds de naam van de argumentvariabelen zien. Dit heeft als gevolg dat we er best voor opteren om zo duidelijk mogelijke identifiers uit te kiezen voor deze argumentvariabelen. Liefst een naam die de rol van de doorgegeven argumentwaarde weerspiegelt.
Gezien het in bovenstaand voorbeeld gaat om een initiële waarde voor een property die ook beschikbaar is voor clients, ligt de keuze voor de identifier van de gerelateerde argumentvariabele voor de hand. Namelijk dezelfde identifier als die voor de gerelateerde property ( Name property en name argumentvariabele ).
Om het voor de compiler duidelijk te houden dat de argumentwaarde moet toegekend worden aan de property ( en niet opnieuw aan de argumentvariabele zelf ) verwijzen we naar deze property door er de objectexpressie Me voor te plaatsen. Me is steeds een verwijzing naar het object dat op dat moment in uitvoering is. Men kan naar eender welke instancemember verwijzen binnen een klasse door voor de identifier van die member Me. te plaatsen, dit is niet noodzakelijk, maar kan eventueel verduidelijken dat het om een aanroep naar een instancemember gaat. Me is enkel noodzakelijk om mogelijke verwarring te vermijden voor de compiler bij het verwijzen een member van het object ( dat op dat moment in uitvoering is ) wanneer een andere member of variabele dezelfde identifier zou gebruiken.
Constructoren worden niet alleen gebruikt voor het instellen van initiële waarden voor eigenschappen. Eender wat moet gebeuren bij het construeren van een object kan men in de constructor coderen. 9.11.1. Default Constructor en MyBaseWat niet opvalt ( omdat het achter de schermen wordt toegevoegd ) is dat elke klasse die je definieert een constructor heeft. Definieer je dus zelf niet expliciet een constructor in een klasse dan wordt er achter de schermen - wat men noemt - een default constructor toegevoegd.
Deze default constructor ziet er steeds als volgt uit : Public Sub New()
MyBase.New()
End SubHet gaat dus om een publiek beschikbare constructor ( access modifier Public ). Deze dient publiek beschikbaar te zijn, anders kan men geen object instantiëren van dit type.
Onderstaande klasse bijvoorbeeld heeft een constructor die ingekapseld is. Visual Basic Broncode Class SomeClass
Private Sub New()
MyBase.New()
End Sub
End Class
Module Client2
Sub Main()
End Sub
End ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Clients hebben hier dus niet de mogelijkheid om een object van dit type te construeren. Het inkapselen van constructoren kan bijvoorbeeld nuttig zijn om het "singleton pattern" te implementeren, hierover later meer.
Uit bovenstaand voorbeeld is ook duidelijk geworden dat indien men zelf expliciet een constructor definieert in een klasse, er geen sprake meer is van de default constructor. Deze wordt dus enkel toegevoegd indien er nog geen aanwezig zou zijn. Voegt men dus bijvoorbeeld een constructor met argumenten toe aan een klasse, dan is men verplicht argumentwaarden op te geven in een object initializer voor het instantiëren van een object van dat type. ( althans wanneer er geen extra argumentloze constructor aanwezig zou zijn )
De default constructor is uiteraard argumentenloos. Het systeem dat achter de schermen deze constructor toevoegt heeft immers geen idee welke parameters van nut zouden kunnen zijn. En bijkomend ook geen idee van hebben wat aan te vangen met de doorgegeven argumentwaarden.
Op de eerste implementatieregel van deze default constructor staat steeds een aanroep naar de parameterloze constructor van de basisklasse. We weten ondertussen dat iedere klasse die we definiëren een afgeleide klasse is. Geven we niet zelf op van welk type onze klasse overerft, dan wordt automatisch overgeërfd van het type System.Object.
Het MyBase keyword is vergelijkbaar met Me, maar kan gebruikt worden om naar members te verwijzen die in de basisklasse zijn gedefinieerd. Dit kan gaan over overgeërfde members of over constructoren van de basisklasse. Constructoren worden immers nooit overgeërfd in Visual Basic, dus een aanroep naar die constructor gedefinieerd in die basisklasse kan enkel aan de hand van het MyBase keyword.
Een verschil tussen Me en MyBase is dat Me een objectexpressie is, in tegenstelling tot MyBase. Een constructie als volgende is bijgevolg NIET mogelijk : Onthoud dus dat bij het construeren van een object steeds alle constructoren van de basisklassen worden uitgevoerd. Bemerk wel dat het by default gaat om een aanroep naar de parameterloze constructor van de basisklasse. Men zal deze default-aanroep moeten vervangen ( door een expliciete call ) naar een niet parameterloze constructor indien de basisklasse niet over een dergelijke parameterloze constructor beschikt. Zoals ook in onderstaand voorbeeld wordt verduidelijkt. Visual Basic Broncode 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
End Class
Module Client3
Sub Main()
Dim student1 As Student = New Student("John", "Group 1")
With student1
Console.WriteLine(.Name)
Console.WriteLine(.ClassGroup)
End With
Console.ReadLine()
End Sub
End ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output John
Group 1 Hier beschikt de klasse Student enkel over een constructor die twee argumentwaarden verwacht ( de default constructor is immers vervangen door de expliciet gedefinieerde constructor ). Dus moet in de client van het type Student in de object initializer ook argumentwaarden voor die argumenten worden opgegeven.
De basisklasse Person beschikt niet over een parameterloze constructor, dus zijn we verplicht een constructor op te nemen in het afgeleide type Student, waarin we dan nog eens verplicht zijn de niet parameterloze constructor van die basisklasse Person aan te roepen ( waarbij we dus de nodige argumentwaarden moeten doorgeven ).
Vaak komt dit handig uit, zo ook in dit voorbeeld, die initialisatiecode die hier de Name eigenschap op een initiële waarde zet, kan zo worden herbruikt, en hoeft niet te worden geherimplementeerd in de constructor van de afgeleide klasse Student.
De aanroep naar de constructor van de basisklasse moet steeds op de eerste regel gebeuren van de constructor van de afgeleide klasse.
Indien er wel een parameterloze constructor in basisklasse was geweest, hadden we niet expliciet een MyBase.New()-call moeten opnemen. Je mag het doen, maar achter de schermen zou deze toch automatisch worden toegevoegd. Terug naar boven 9.11.2. Meerdere Constructoren in Een KlasseIn 1 klasse kunnen meerdere constructoren worden opgenomen, dit is een vorm van method overloading. Visual Basic Broncode Class Teacher : Inherits Person
Public Sub New(ByVal name As String)
MyBase.New(name)
End Sub
Public Sub New(ByVal name As String, ByVal course As String)
Me.New(name)
Me.Course = course
End Sub
Private m_Course As String
Public Property Course() As String
Get
Course = m_Course
End Get
Set(ByVal value As String)
m_Course = value
End Set
End Property
End Class
Module Client4
Sub Main()
Dim teacher1 As Teacher = New Teacher("John")
Console.WriteLine(teacher1.Name)
Console.WriteLine(teacher1.Course)
Dim teacher2 As Teacher = New Teacher("Jane", "Visual Basic")
Console.WriteLine(teacher2.Name)
Console.WriteLine(teacher2.Course)
Console.ReadLine()
End Sub
End ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Visual Basic Output John
Jane
Visual Basic Een aanroep als Me.New(...) kan indien je in de constructor een andere constructor van die klasse wenst aan te roepen. Deze call wordt verwezenlijkt nog voordat de constructor van de basisklasse wordt aangeroepen. Terug naar boven
9.11.3. ReadOnly VeldenNaast ReadOnly properties ( die enkel instelbaar zijn, en dus enkel over een "setter" beschikken ) kan men ook ReadOnly velden declareren.
Aan deze ReadOnly velden kan enkel een waarde worden toegekend in de constructor. Visual Basic Broncode Class Product
Private m_Price As Decimal
Private ReadOnly m_TaxPercentage As Decimal
Public Sub New(ByVal taxPercentage As Decimal)
m_TaxPercentage = taxPercentage
End Sub
Public ReadOnly Property TaxPercentage() As Decimal
Get
TaxPercentage = m_TaxPercentage
End Get
End Property
Public Property Price() As Decimal
Get
Price = m_Price
End Get
Set(ByVal value As Decimal)
m_Price = value
End Set
End Property
Public Function GetPriceIncludingTax() As Decimal
GetPriceIncludingTax = Price * (1 + (TaxPercentage / 100))
End Function
End Class
Module Client5
Sub Main()
Dim product1 As Product = New Product(10)
product1.Price = 100
Console.WriteLine(product1.GetPriceIncludingTax())
Console.ReadLine()
End Sub
End ModuleDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
In bovenstaand voorbeeld wordt een TaxPercentage waarde beschouwd als een toestand die per Product object configureerbaar moet zijn ( dus een instancegerelateerde toestand ). Hiervoor kunnen we dus een veld gebruiken om de toestandswaarde te stockeren.
Maar de TaxPercentage-toestand wordt hier ook beschouwd als een onwijzigbare toestand. Wat we kunnen bekomen en garanderen door het gebruikte veld ReadOnly te declareren. Terug naar boven
9.11.4. OefeningenOpgave 1 :
Wat is de uitvoer van volgend voorbeeld ? Visual Basic Broncode Module Exercise1Task
Sub Main()
Dim object2 As Class2 = New Class2
Console.WriteLine(object2.Value1)
Console.WriteLine(object2.Value2)
Console.ReadLine()
End Sub
End Module
Class Class1
Public Value1 As Integer
Public Sub New()
Value1 = 1
End Sub
End Class
Class Class2 : Inherits Class1
Public Value2 As Integer
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Oplossing 1 : Opgave 2 : Wat is de uitvoer van volgend voorbeeld ? Visual Basic Broncode Module Exercise2Task
Sub Main()
Dim object4 As Class4 = New Class4
Console.WriteLine(object4.Value1)
Console.WriteLine(object4.Value2)
Console.ReadLine()
End Sub
End Module
Class Class3
Public Value1 As Integer
Public Sub New()
Value1 = 3
End Sub
End Class
Class Class4 : Inherits Class3
Public Value2 As Integer
Public Sub New()
Value2 = Value1 * 4
End Sub
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Oplossing 2 : Opgave 3 : Wat is de uitvoer van volgend voorbeeld ? Visual Basic Broncode Module Exercise3Task
Sub Main()
Dim object6 As Class6 = New Class6
Console.WriteLine(object6.Value1)
Console.WriteLine(object6.Value2)
object6 = New Class6(10)
Console.WriteLine(object6.Value1)
Console.WriteLine(object6.Value2)
Console.ReadLine()
End Sub
End Module
Class Class5
Public Value1 As Integer
Public Sub New()
Value1 = 2
End Sub
Public Sub New(ByVal value As Integer)
Value1 = value
End Sub
End Class
Class Class6 : Inherits Class5
Public Value2 As Integer
Public Sub New()
MyBase.New(5)
Value2 = Value1 * 6
End Sub
Public Sub New(ByVal value As Integer)
MyBase.New()
Value2 = Value1 * 6
End Sub
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Oplossing 3 : Visual Basic Output 5
30
2
12 Opgave 4 : Wat is de uitvoer van volgend voorbeeld ? Visual Basic Broncode Module Exercise4Task
Sub Main()
Dim object8 As Class8 = New Class8
Console.WriteLine(object8.Value1)
Console.WriteLine(object8.Value2)
Console.ReadLine()
End Sub
End Module
Class Class7
Public Value1 As Integer
Public Sub New()
End Sub
Public Sub New(ByVal value As Integer)
Value1 = value
End Sub
End Class
Class Class8 : Inherits Class7
Public Value2 As Integer
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Oplossing 4 : Opgave 5 : Wat is de uitvoer van volgend voorbeeld ? Visual Basic Broncode Module Exercise5Task
Sub Main()
Dim object10 As Class10 = New Class10
Console.WriteLine(object10.Value1)
Console.WriteLine(object10.Value2)
Console.ReadLine()
End Sub
End Module
Class Class9
Public Value1 As Integer
Public Sub New()
End Sub
Public Sub New(ByVal value As Integer)
Value1 = value
End Sub
End Class
Class Class10 : Inherits Class9
Public Value2 As Integer
Public Sub New()
Value2 = 2
End Sub
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Oplossing 5 : Opgave 6 : Wat is de uitvoer van volgend voorbeeld ? Visual Basic Broncode Module Exercise6Task
Sub Main()
Dim object12 As Class12 = New Class12
Console.WriteLine(object12.Value1)
Console.WriteLine(object12.Value2)
Console.ReadLine()
End Sub
End Module
Class Class11
Public Value1 As Integer
Public Sub New()
End Sub
Public Sub New(ByVal value As Integer)
Value1 = value
End Sub
End Class
Class Class12 : Inherits Class11
Public Value2 As Integer
Public Sub New()
MyBase.New(1)
Value2 = 2
End Sub
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Oplossing 6 : Opgave 7 : Wat is de uitvoer van volgend voorbeeld ? Visual Basic Broncode Module Exercise7Task
Sub Main()
Dim object14 As Class14 = New Class14(1, 2)
Console.WriteLine(object14.Value1)
Console.WriteLine(object14.Value2)
Console.ReadLine()
End Sub
End Module
Class Class13
Public Value1 As Integer
Public Sub New(ByVal value As Integer)
Value1 = value
End Sub
End Class
Class Class14 : Inherits Class13
Public Value2 As Integer
Public Sub New(ByVal value1 As Integer, ByVal value2 As Integer)
MyBase.New(value1)
Me.Value2 = value2
End Sub
End ClassDownload Visual Basic Broncode Bekijk deze Broncode in Visual C#
Oplossing 7 : Opgave 8 : Schrijf een klasse Counter. Van een Counter object kan je de waarde opvragen. Voorzie ook methods om de waarde te verhogen en te verlagen. De verhoog- en verlaag-stapwaarde mag hier steeds 1 zijn.
Het is verplicht bij het instantiëren van een Counter object een initiële waarde op te geven. Oplossing 8 : Visual Basic Broncode Class Counter
Public Sub New(ByVal value As Integer)
m_Value = value
End Sub
Protected m_Value As Integer
Public Function GetValue() As Integer
GetValue = m_Value
End Function
Public Sub Raise()
m_Value += 1
End Sub
Public Sub Lower()
m_Value -= 1
End Sub
End Class
Module Exercise8Solution
Sub Main()
Dim counter1 As Counter = New Counter(5)
Console.WriteLine(counter1.GetValue() = 5)
Console.ReadLine()
End Sub
End ModuleDownload 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
|