Zie Scherp Scherper - Hoofdstuk 11
Na dit hoofdstuk kan je:
een constructor schrijven om de beginstaat van een object in te stellen
het verschil tussen een default en een overloaded constructor uitleggen
constructors hergebruiken met this()
objecten opzetten met object initializer syntax en required
het keyword static gebruiken voor fields, methoden, properties en klassen
uitleggen waarom een static deel niet bij de niet-static delen kan
Een klasse bestond tot nu uit:
instantievariabelen
de toestand
methoden
het gedrag
properties
gecontroleerde toegang
Daar komen nu bij:
constructors
static
object initializer syntax
new doet drie dingen:
1. een object aanmaken in de heap
2. de constructor aanroepen voor extra initialisatie
3. een referentie naar dat object teruggeven
Vandaar de ronde haakjes bij
new Student(): dat is de constructor-aanroep.
Geen zelf geschreven constructor
je krijgt gratis een onzichtbare default constructor
Enkel een default constructor (zonder parameters)
maar zelf ingevuld
Een of meer overloaded constructors
met parameters, bv. new Student("Jos")
Waarschuwing
Net als met aannemers: soms ruimen ze zelf op, soms niet. Schrijf je zelf een constructor, dan ben je de gratis default constructor kwijt.
Altijd public
geen returntype
naam = klassenaam
( ) geen parameters
Tip
Enkel een auto-property een startwaarde geven? Dan volstaat public int X { get; set; } = 2; zonder constructor.
Zo kan je new Student("Lord Oakenwood") schrijven.
Waarschuwing
Vanaf nu werkt new Student() niet meer: “Student does not contain a constructor that takes 0 arguments”. Wil je de default constructor terug? Schrijf hem dan zelf.
Stel: drie constructors die elk Naam, Adres en Saldo instellen.
constructor 1
Naam Adres Saldo
constructor 2
Naam Adres Saldo
constructor 3
Naam Adres Saldo
Splits je later Adres op in Straat + Stad, dan moet je elke constructor apart aanpassen.
Waarschuwing
Code die je op meerdere plekken herhaalt, is vragen om problemen. Eén bron van waarheid is beter.
Vermijd dubbele code door één constructor de andere te laten aanroepen:
De compiler kiest via overload resolution de juiste constructor.
Minstens genoeg om een object in een geldige staat te brengen:
Tip
Door enkel deze constructor te voorzien, dwing je af dat niemand een Breuk() zonder noemer maakt (en zo een DivideByZeroException riskeert).
Geef bij de creatie properties een beginwaarde, zonder een aparte constructor:
Werkt via de default constructor en daarna de properties
Enkel voor properties met een van buitenaf bereikbare set
Opmerking
Intern: eerst de default constructor, dan m.Temperatuur = 3.4; enzovoort.
Wil je toch verplichten dat een property wordt ingesteld bij object initializer syntax? Gebruik required:
Belangrijk
required bestaat sinds C# 11 (.NET 7+).
static geeft aan dat een element bij de klasse zelf hoort, niet bij een individueel object.
Gevolg:
je kan het aanroepen zonder een object aan te maken
de data wordt gedeeld over alle objecten
static kan op fields methoden properties en zelfs de hele klasse
Eén exemplaar, gedeeld door alle objecten: maak je drie Mens-objecten, dan staat teller op 3.
Waarschuwing
Gebruik static met mate: het druist vaak in tegen OOP. Het past bij zaken die bij de klasse horen (een teller), niet bij een individueel object (een geboortejaar).
Daarom kan je Math.Pow(3, 2) zonder een Math-object te maken:
Belangrijk
Een static class mag enkel static members bevatten. De compiler dwingt dat af: je kan er toch nooit een object van maken.
Een static methode kan enkel andere static leden aanspreken: ze hoort bij geen enkel object.
Tip
Daarom moet in Program.cs alles static zijn: Main is zelf static.
Alle balletjes delen dezelfde speelveldgrenzen:
Elk balletje gebruikt in Update() gewoon Balletje.Breedte, zonder de grenzen zelf te kennen.
Een nieuwe Random bij elke worp is een slecht idee. Met een vaste seed (om te testen) gooit elke worp hetzelfde getal, en zonder seed maak je telkens een object aan dat je meteen weer weggooit.
Tip
Eén gedeelde, static generator lost dat netjes op: de afspraak uit hoofdstuk 4, één generator voor je hele programma.
Een tekst-avontuur waarin de speler van kamer naar kamer wandelt:
Room
RoomDescribe() die de kamer en de uitgangen toont Player
HuidigeKamer bijMoveTo(richting) om (te proberen) verplaatsenTip
Een object dat een ander object als instantievariabele bevat: de kern van grotere OOP-programma’s. Uitbreiding: geef sommige kamers een NPC met een Speak()-tip.
De constructor zet een object meteen in een geldige beginstaat (via new)
Schrijf je zelf een constructor, dan ben je de gratis default constructor kwijt
this() hergebruikt constructors; object initializer syntax en required vullen properties in
static hoort bij de klasse, niet bij een object: gedeelde data en hulpmethoden
Een static deel kan enkel andere static delen aanspreken
Tip
Volgende halte: arrays en collecties van objecten (List, foreach, Dictionary).
Kennisclips
Hoe doen andere programmeertalen hetzelfde? En een korte zoek-de-fout, om zo kritisch mogelijk naar code te leren kijken.
C#, Java en C++
laten meerdere constructors toe (overloading)
Python kent dat niet
één __init__, en je lost het op met default-parameterwaarden
Zowel Student("Jos") als Student("Jos", True) werkt: één constructor die zich als meerdere gedraagt.
In Java werkt static zo goed als identiek aan C#:
In alle gevallen hoort dit bij de klasse, niet bij een los object.
Onderstaande Java-klasse wil bijhouden hoeveel fietsen er gemaakt zijn, maar de teller blijft hangen op 1. Wat loopt er mis?
Opmerking
aantalFietsen is hier een gewone instantievariabele, dus elk Fiets-object krijgt z’n eigen kopie die in de constructor van 0 naar 1 gaat. Je wilt één teller die gedeeld wordt over alle objecten, dus moet de variabele static zijn: static int aantalFietsen = 0;. Dezelfde redenering geldt in C#.
Een handige samenvattende poster (Opgelet: gemaakt m.b.v. ChatGPT Image Gen 2).