- Let op Kopieer geen code van de parent naar de child. Wat de parent al doet, roep je op met
base.Methode()ofbase(...), en wat de child erft, declareer je niet opnieuw (boeteblad). - Een methode overschrijven doe je met
virtualin de parent enoverridein de child. Meldt de compilerhides inherited member, dan ben jeoverridevergeten: je programma start, maar via een variabele van het parent-type draait de versie van de parent (uitleg). - Heeft de parent enkel een constructor met parameters, dan roept elke child die op met
base(...)achter haar constructorkop (uitleg). - Moet de child aan iets van de parent, maak het dan
protected, nietpublic. Bij een property volstaat{ get; protected set; }(uitleg).
Is een of heeft een?
Voor je een klasse laat erven, stel je de vraag uit het boek: is een X een Y? Bekijk de tien paren hieronder. Kies telkens:
- overerving: de eerste klasse is een tweede, dus
class Eerste : Tweede; - heeft een: de ene klasse heeft een andere, en dat is geen overerving;
- geen van beide.
Schrijf er telkens in één zin bij waarom. Twee paren zijn strikvragen.
StudentenPersoonKotenKoelkastLectorenPersoonFietsenBelKlasenStudentElixerenDrankFietsenAutoPinguinenVogel, als de klasseVogeleen methodeVlieg()heeftVierkantenRechthoek, als de klasseRechthoekeen methodeMaakBreder(int cm)heeft die enkel de breedte verandertPegasus, het vliegende paard uit de Griekse mythen, en de klassenPaardenVogel: magclass Pegasus : Paard, Vogel?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Overerving past bij “is een”. Bij “heeft een” krijgt een klasse een instantievariabele of property van de andere klasse, daar komt hoofdstuk 15 op terug.
- Ook een “is een” die in gewone taal klopt, controleer je: kan de child echt alles wat de parent kan?
- Zie Is-een relatie en Multiple inheritance.
Magische dranken (Essential) (GPT)
In deze opdracht ontwerp je een systeem waarin dranken niet alleen dorst lessen, maar ook magische krachten hebben. Van gewone drankjes tot zeldzame elixers: elke slok telt!

- Maak een klasse
Drankmet:- een property
Naam; - een constructor die de naam instelt;
- een
virtualmethodeBerekenKracht()die 50 teruggeeft.
- een property
- Maak een klasse
Elixerdie erft vanDrank, met een extra propertyIsZeldzaamdie je via de constructor instelt.- Overschrijf
BerekenKracht(): vraag eerst de basiskracht op metbase.BerekenKracht()en tel er een bonus bij: 20 als het elixer zeldzaam is, anders 10.
- Overschrijf
Krijg je bij de constructor van Elixer de fout CS7036 There is no argument given that corresponds to the required parameter 'naam' of 'Drank.Drank(string)'? Lees dan in het boek wat base(...) doet bij constructors.
Testcode. Zet deze code in je Main. Je code werkt als je exact deze uitvoer krijgt.
Drank cola = new Drank("Gewone cola");
Elixer mystiek = new Elixer("Mystiek elixer", true);
Elixer standaard = new Elixer("Standaard elixer", false);
Console.WriteLine($"{cola.Naam} heeft kracht {cola.BerekenKracht()}");
Console.WriteLine($"{mystiek.Naam} heeft kracht {mystiek.BerekenKracht()}");
Console.WriteLine($"{standaard.Naam} heeft kracht {standaard.BerekenKracht()}");Gewone cola heeft kracht 50
Mystiek elixer heeft kracht 70
Standaard elixer heeft kracht 60
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Met
base.BerekenKracht()gebruik je de 50 van de parent in plaats van ze over te typen. Verandert de basiskracht ooit, dan pas je ze op één plaats aan. - Heeft de parent geen constructor zonder parameters, dan roept de child er een op met
base(...).
Een avond karaoke (Essential)
Na de laatste examendag huur je met je vrienden een karaokebox. De zaak rekent 50 euro voor de box, plus 20 euro per uur. Toon je een studentenkaart, dan krijg je 10% korting op het totaal.
Deel 1. Maak een klasse Boeking met:
- een property
Naam, op wiens naam de box geboekt is, en een propertyUren(int); - een constructor die beide instelt;
- een
virtualmethodeBerekenKost()die de totale kost alsdoubleteruggeeft: 50 euro plus 20 euro per uur. Zet de twee bedragen in eenconst; - een methode
ToonInfo()die de naam, het aantal uur en de kost toont, zoals in de testcode van deel 2.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 2. Maak een klasse StudentenBoeking die erft van Boeking. Ze heeft alles wat een gewone boeking heeft, maar ze geeft 10% korting op de kost.
Testcode. Zet deze code in je Main. Je code werkt als je exact deze uitvoer krijgt.
Boeking jos = new Boeking("Jos", 3);
jos.ToonInfo();
StudentenBoeking mira = new StudentenBoeking("Mira", 3);
mira.ToonInfo();
Boeking kot = new StudentenBoeking("Kot Zuidstraat", 1);
kot.ToonInfo();Jos: 3 uur, 110 euro
Mira: 3 uur, 99 euro
Kot Zuidstraat: 1 uur, 63 euro
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 3. Aan ToonInfo heb je in StudentenBoeking niets veranderd. Waarom toont Mira dan toch 99 euro en geen 110? En waarom toont kot 63 euro, terwijl de variabele van het type Boeking is?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Een child overschrijft enkel wat anders is.
ToonInfohoeft niet mee, want ze gebruiktBerekenKost, en die isvirtual. - Een object van een child-klasse mag in een variabele van het parent-type. De override draait dan toch. Het waarom komt in hoofdstuk 16.
- Zie Het base keyword.
Het dierenrijk

Bouw deze klassen na. Dier is de parent van Zoogdier en Reptiel, Zoogdier is de parent van Konijn, Koe en Hond, en zo verder. Hond en Leguaan zijn optioneel.
- Geef elke klasse één property die haar parent niet heeft. Bijvoorbeeld:
DierkrijgtNaamenIsUitgestorven,ZoogdierkrijgtBiotoop,ReptielkrijgtAantalSchubben. Verzin de rest zelf. - Geef
DiereenvirtualmethodeToonInfo()die zijn properties toont. Elke child overschrijftToonInfo(): ze roept eerstbase.ToonInfo()op en toont daarna enkel haar eigen property. - Je maakt een
Konijnaan en roeptToonInfo()op. Schrijf eerst op papier welke regels verschijnen, in welke volgorde, en uit welke klasse elke regel komt. Probeer het daarna uit. - Maak van elke klasse een object, zet ze allemaal in een
List<Dier>en roep in eenforeachbij elk dierToonInfo()op. Welke versie vanToonInfodraait er bij de koe?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Elke override begint met
base.ToonInfo()en voegt één regel toe. Zo staat elke property op één plaats, ook over drie niveaus. baseroept de parent op, en die roept op haar beurt haar eigen parent op.- Zie Het base keyword.
Voorspel de uitvoer: de repetitie van de studentenband (Essential)
Je studentenband schrijft een programma om de instrumenten klaar te zetten voor de repetitie. Er zijn drie klassen, elk in een eigen bestand:
internal class Instrument
{
public Instrument()
{
Console.WriteLine("Instrument gestemd");
}
public Instrument(int snaren)
{
Console.WriteLine($"Instrument met {snaren} snaren");
}
public virtual void Speel()
{
Console.WriteLine("Plink");
}
}internal class Gitaar : Instrument
{
public Gitaar() : base(6)
{
Console.WriteLine("Gitaar klaar");
}
public override void Speel()
{
Console.WriteLine("Tokkel");
base.Speel();
}
}internal class ElektrischeGitaar : Gitaar
{
public ElektrischeGitaar()
{
Console.WriteLine("Versterker aan");
}
}Deel 1. Schrijf op papier wat dit programma toont, lijn per lijn. Typ de code pas daarna over en vergelijk.
Instrument triangel = new Instrument();
Console.WriteLine("---");
Instrument gitaar = new ElektrischeGitaar();
Console.WriteLine("---");
gitaar.Speel();
Console.WriteLine("---");
triangel.Speel();Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 2. Haal de constructor zonder parameters uit Instrument weg. Hoeveel fouten geeft de compiler, en waar? Waarom geeft ElektrischeGitaar geen fout?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 3. Zet de constructor terug. Er mag geen klasse meer van Gitaar erven. Welk keyword zet je bij Gitaar, en wat zegt de compiler dan?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Bij het aanmaken van een object draaien de constructors van boven naar beneden: eerst de verste voorouder, als laatste de klasse zelf.
- Zonder
base(...)draait de constructor zonder parameters van de parent. Metbase(...)kies je zelf welke. base.Speel()mag overal in een override staan, ook na je eigen code.- Zie Volgorde van constructors en sealed.
Stevens dierentuin (Essential)
Stagiair Steven werkt voor de dierentuin. Hij moest een klasse Dier schrijven en een klasse Leeuw die ervan erft: een leeuw eet anders en maakt een ander geluid dan een gewoon dier. Een A.I. leverde dit, en Steven plakte het zonder nalezen in zijn project.
De klasse Dier:
internal class Dier
{
private int kiloVoerPerDag;
public string Naam { get; private set; }
public Dier(string naam, int kiloVoer)
{
Naam = naam;
kiloVoerPerDag = kiloVoer;
}
public void Eet()
{
Console.WriteLine($"{Naam} eet {kiloVoerPerDag} kg voer.");
}
public virtual void MaakGeluid()
{
Console.WriteLine($"{Naam} maakt geluid.");
}
}De klasse Leeuw:
internal class Leeuw : Dier
{
public bool IsMannetje { get; private set; }
public Leeuw(string naam, int kiloVlees, bool isMannetje)
{
IsMannetje = isMannetje;
}
public override void Eet()
{
Console.WriteLine($"{Naam} verslindt {kiloVoerPerDag} kg vlees.");
}
public void MaakGeluid()
{
if (IsMannetje)
{
Console.WriteLine($"{Naam} brult: ROAAAR!");
}
else
{
Console.WriteLine($"{Naam} gromt.");
}
}
}En in Main:
Dier kameel = new Dier("Kamiel", 12);
Dier leeuw = new Leeuw("Simba", 7, true);
kameel.Eet();
kameel.MaakGeluid();
leeuw.Eet();
leeuw.MaakGeluid();Deel 1. Zet elke klasse in een eigen bestand en compileer. De compiler meldt één fout en één waarschuwing. Los de fout op. De waarschuwing laat je voorlopig staan.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 2. Compileer opnieuw. Nu verschijnen er twee nieuwe fouten. Los ze allebei op, zonder Dier een extra constructor te geven.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 3. Het programma compileert nu, met enkel nog de waarschuwing van deel 1. Voer het uit. Welke lijn klopt niet? Zoek de vierde fout. Wat had de waarschuwing je al verteld?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- De compiler meldt niet alle fouten tegelijk. Los de fout op die je ziet, en compileer opnieuw.
virtualenoverridehoren per methode bij elkaar. De A.I. zettevirtualbijMaakGeluidenoverridebijEet, en dus klopte geen van beide.- Een waarschuwing laat je programma starten, maar CS0114 wees hier net naar de enige fout die de compiler niet tegenhield. Zie de waarschuwing over hiding in Een voorbeeld met vliegende objecten.
- Test een override via een variabele van het type van de parent. Via
Leeuwzie je hiding niet. - Zie ook protected keyword en Overloaded constructors en base().
Pakjes per drone (Final Essentials) (GPT)
De campusbib levert boeken voortaan per drone. Jij schrijft de software die de vloot laat vliegen.
Deel 1: de klasse Drone. Maak een klasse Drone met:
- een property
Model(string) en een propertyBatterij(int), allebei met eenprivate set; - een constructor met het model als parameter. De batterij start op 100;
- een
protected virtualmethodeBerekenVerbruik()die teruggeeft hoeveel procent batterij één vlucht kost: 5; - een
protected virtualmethodeBeschrijving()die de tekstvliegt rondteruggeeft; - een gewone methode
Vlieg(), dus nietvirtual. Ze trekt het verbruik af van de batterij (nooit onder 0) en toont één regel:[Model] [Beschrijving]. Batterij: [Batterij]%. Is de batterij daarna lager dan 20, dan toont ze ookWaarschuwing: batterij bijna leeg!.
BerekenVerbruik en Beschrijving zijn protected: enkel Vlieg en de childs hebben ze nodig, Main niet.
Deel 2: twee soorten drones.
LeverDroneerft vanDroneen heeft een extra propertyGewicht(int): hoeveel kilo boeken hij meeneemt. Een vlucht kost 5 plus 1 per kilo. Met 4 kg boeken is dat 9 procent batterij per vlucht. De beschrijving islevert [Gewicht] kg boeken.RaceDroneerft vanDroneen heeft een extra propertyTopsnelheid(int). Een vlucht kost 5 meer dan bij een gewone drone, dus 10 procent batterij. De beschrijving isracet aan [Topsnelheid] km/u.
Beide childs krijgen een constructor met het model en hun eigen extra waarde. Gebruik in BerekenVerbruik de versie van de parent, en zet de waarschuwing niet in de childs: die staat al in Vlieg.
Deel 3: de vloot. Maak in Main een List<Drone> met een gewone drone Verkenner, een leverdrone Boekenwurm met 4 kg boeken en een racedrone Bliksem die 120 km/u haalt. Laat de vloot ronde na ronde vliegen, zolang er nog minstens één drone batterij heeft. Een drone met 0% vliegt niet meer. Schrijf die stopvoorwaarde zelf met een bool, zonder LINQ.
Het begin van de uitvoer:
--- Ronde 1 ---
Verkenner vliegt rond. Batterij: 95%
Boekenwurm levert 4 kg boeken. Batterij: 91%
Bliksem racet aan 120 km/u. Batterij: 90%
--- Ronde 2 ---
Verkenner vliegt rond. Batterij: 90%
Boekenwurm levert 4 kg boeken. Batterij: 82%
Bliksem racet aan 120 km/u. Batterij: 80%
Ronde 10 tot en met 13:
--- Ronde 10 ---
Verkenner vliegt rond. Batterij: 50%
Boekenwurm levert 4 kg boeken. Batterij: 10%
Waarschuwing: batterij bijna leeg!
Bliksem racet aan 120 km/u. Batterij: 0%
Waarschuwing: batterij bijna leeg!
--- Ronde 11 ---
Verkenner vliegt rond. Batterij: 45%
Boekenwurm levert 4 kg boeken. Batterij: 1%
Waarschuwing: batterij bijna leeg!
--- Ronde 12 ---
Verkenner vliegt rond. Batterij: 40%
Boekenwurm levert 4 kg boeken. Batterij: 0%
Waarschuwing: batterij bijna leeg!
--- Ronde 13 ---
Verkenner vliegt rond. Batterij: 35%
Na ronde 20 staat ook Verkenner op 0% en stopt het programma.
Wil je het als echte vlucht zien? Zet System.Threading.Thread.Sleep(500); aan het einde van elke ronde.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Een gewone methode in de parent kan
virtualmethoden oproepen die elke child op haar manier invult. Zo staat de gemeenschappelijke code, hier het aftrekken en de waarschuwing, maar één keer in je programma. protectedwerkt ook voor methoden: de childs kunnen ze overschrijven,Mainkan ze niet oproepen.- Eén
List<Drone>volstaat voor alle soorten drones.
Ballspel met overerving
Deze oefening is een bonus. Ze bouwt verder op het Pong-voorbeeld uit hoofdstuk 9 en op Pong overerving in het boek.
Je kent het Balletje uit het boek. Hier krijgt het een constructor, en zijn properties hebben een protected set: Main kan ze enkel lezen, child-klassen kunnen ze ook aanpassen. Update en TekenOpScherm zijn virtual. Kopieer de klasse naar een nieuw project:
internal class Balletje
{
public int X { get; protected set; }
public int Y { get; protected set; }
public int VX { get; protected set; }
public int VY { get; protected set; }
public Balletje(int x, int y, int vx, int vy)
{
X = x;
Y = y;
VX = vx;
VY = vy;
}
public virtual void Update()
{
if (X + VX >= Console.WindowWidth || X + VX < 0)
{
VX = -VX;
}
X = X + VX;
if (Y + VY >= Console.WindowHeight || Y + VY < 0)
{
VY = -VY;
}
Y = Y + VY;
}
public virtual void TekenOpScherm()
{
Console.SetCursorPosition(X, Y);
Console.Write("O");
}
public static bool Raakt(Balletje bal1, Balletje bal2)
{
return bal1.X == bal2.X && bal1.Y == bal2.Y;
}
}En dit spelletje: de speler moet met de pijltjestoetsen het balletje raken.
static void Main(string[] args)
{
Console.CursorVisible = false;
Balletje bal = new Balletje(4, 4, 1, 1);
SpelerBalletje speler = new SpelerBalletje(10, 10);
bool gewonnen = false;
while (!gewonnen)
{
Console.Clear();
bal.Update();
bal.TekenOpScherm();
if (Console.KeyAvailable)
{
speler.VeranderRichting(Console.ReadKey(true).Key);
}
speler.Update();
speler.TekenOpScherm();
if (Balletje.Raakt(bal, speler))
{
gewonnen = true;
}
System.Threading.Thread.Sleep(100);
}
Console.Clear();
Console.WriteLine("Gewonnen!");
}Console.KeyAvailable is true als de gebruiker een toets heeft ingedrukt, en Console.ReadKey(true).Key geeft die toets terug zonder ze op het scherm te zetten. Dat stuk hoef je niet zelf te schrijven.
Deel 1. Schrijf de klasse SpelerBalletje, die erft van Balletje:
- een constructor met enkel
xeny. Het balletje van de speler staat bij de start stil; - een methode
VeranderRichting(ConsoleKey toets): pijltje omhoog maaktVY1 kleiner, omlaag 1 groter, links maaktVX1 kleiner, rechts 1 groter. Gebruik eenswitchmetcase ConsoleKey.UpArrow:enzovoort; - een override van
TekenOpSchermdie een groeneXtekent in plaats van eenO.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 2. Schrijf een klasse CentreerBalletje: een balletje dat naar het midden van het scherm springt als het de linker- of rechterkant raakt, zoals in het boek. Gebruik base.Update() voor de rest van de beweging. Vervang in Main het gewone balletje door Balletje bal = new CentreerBalletje(4, 4, 1, 1);. De rest van Main blijft hetzelfde.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Uitbreidingen. Probeer gerust:
- een
List<Balletje>met meerdere balletjes, gewone en centreerballetjes door elkaar, die je met éénforeachlaat bewegen; - een score: tel de rondes tot de speler raakt;
- levels: na elke treffer een balletje meer;
- PRO: balletjes die tegen elkaar botsen.
- Met
protected setkanMainde positie enkel lezen, maar mogen de childs ze aanpassen. - Een child overschrijft enkel wat anders is.
SpelerBalletjebeweegt zoals elk balletje en tekent zich anders,CentreerBalletjetekent zich zoals elk balletje en beweegt anders.