Zie Scherp Scherper - Hoofdstuk 13
Na dit hoofdstuk kan je:
uitleggen wat overerving is en wanneer de is-een-relatie geldt
een child-klasse maken met de :-notatie
het protected-keyword en de regels rond private toepassen
begrijpen hoe constructors bij overerving samenwerken (base())
methoden aanpassen met virtual en override
de parent-implementatie hergebruiken met base
We deden al abstractie en encapsulatie. Nu: inheritance.
Programmeurs zijn lui
dubbele code = dubbel zoveel bugs
Hebben Monster en Held veel gemeen?
Dan delen ze wellicht een voorouder (Karakter)
De gemeenschappelijke code verhuist naar de parent; de child houdt enkel zijn specialisatie.
Een vuistregel tegen dubbele code:
Eén keer copy-pasten mag. Doe je het een derde keer, dan is het tijd om te refactoren.
Overerving is daarbij vaak het gereedschap: gemeenschappelijke code verhuist naar een parent.
Tip
Refactoren doe je in babystapjes: herstructureer beetje bij beetje, en test tussendoor.
“x is een y” wijst op overerving
een paard is een dier
een tulp is een plant
Kom je in een opgave is, was, zijn tegen, dan is overerving wellicht mogelijk.
Belangrijk
“x heeft een y” is géén overerving, maar associatie (volgend hoofdstuk).
Een Paard kan alles wat een Dier kan, plus zijn eigen specialisatie:
De child erft alles
methoden properties instantievariabelen
Een child-object is dus opgebouwd uit een parent-deel plus zijn eigen specialisatie.
Belangrijk
private blijft private: de child erft het wel, maar mag er niet rechtstreeks aan.
Wil je dat children er wél bij kunnen, maar de buitenwereld niet? Gebruik protected:
Tip
Nog netter: een property met protected set, zodat de instantievariabele beschermd blijft.
In C# erft een klasse van maximaal één parent.
Dat vermijdt het diamond problem: erf je van twee parents met dezelfde methode, welke geldt dan?
Meerdere “rollen” combineren doe je later met interfaces (hoofdstuk 16)
Tip
Denk aan een vogelbekdier: tegelijk vogel en zoogdier. Erfde het van allebei, met welke LegEi() of GeefMelk() moet de compiler dan werken? C# omzeilt die patstelling.
Opmerking
Wil je net verhinderen dat iemand van je klasse erft? Zet er sealed voor.
Maak je een child-object, dan lopen de constructors in volgorde:
1. eerst de verste voorouder
bovenaan de keten
2. dan elke tussenliggende parent
3. ten slotte de klasse zelf
Tip
Logisch: de child heeft de fundering van zijn parent nodig voor hij zelf iets kan doen.
Achter elke child-constructor staat impliciet : base() (de default constructor van de parent). Heeft de parent enkel een overloaded constructor, dan moet je die expliciet aanroepen:
internal class Gebouw
{
public int AantalVerdiepingen { get; private set; }
public Gebouw(int verdiepingenIn) { AantalVerdiepingen = verdiepingenIn; }
}
internal class Huis : Gebouw
{
public bool HeeftTuintje { get; private set; }
public Huis(bool heeftTuin, int aantalVer) : base(aantalVer)
{
HeeftTuintje = heeftTuin;
}
}new Huis(true, 1): de child houdt heeftTuin zelf, en sluist aantalVer door naar de parent.
new Huis(true, 5):
Huis startbase(5) aanGebouw zet AantalVerdiepingenHuis: HeeftTuintje = trueStandaard mag een child de werking van de parent niet zomaar wijzigen. De parent moet dat toelaten met virtual; de child gebruikt override:
virtual mag op alles behalve private (en niet op static)
virtual is een mogelijkheid, geen verplichting om te overriden
De signatuur van de override moet identiek zijn aan die van de parent
Waarschuwing
Vergeet je override (en schrijf je gewoon public void Vlieg()), dan krijg je een new-waarschuwing: C# denkt dat je de methode wil verbergen (hiding), niet overschrijven.
In een spel is Mol een specialisatie van Deelnemer:
Tip
Mol is een Deelnemer (niet omgekeerd). Hij erft alles, maar past enkel zijn slaagkans aan.
Wil je de parent-versie hergebruiken en uitbreiden? Roep ze aan met base:
Zo blijft de basislogica op één plek staan: verandert de basisprijs, dan klopt alles nog.
Een jager bouwt voort op de techniek van de Oermens (base) en doet er 20 kg bovenop.
Maak Update in Balletje virtual en bouw een nieuw soort balletje:
Balletje blijft onaangeroerd; de nieuwe functionaliteit zit in de child.
Bouw voort op de Crazy House: elke kamer is nu een specialisatie van Room.
MonsterRoom
toont een monster in de beschrijving
TreasureRoom
houdt bij hoeveel goud er ligt
TrapRoom
doet schade
BossRoom
monsterkamer met veel meer levens
VampireRoom
enkel ’s nachts actief
Tip
Elke kamer overridet Describe(). Omdat MonsterRoom een Room is, past hij overal waar een Room past (polymorfisme, hoofdstuk 16). Startproject: RoomWalkerDemo2025.
Overerving geldt bij een echte is-een-relatie; de child specialiseert de parent
De child erft alles, maar private blijft afgeschermd; protected opent het voor children
Constructors lopen van parent naar child; met base() kies je de juiste parent-constructor
virtual + override laten een child de werking aanpassen
Met base hergebruik je de parent-implementatie binnen een override
Tip
Volgende halte: gevorderde overerving: System.Object, abstract en eigen exceptions.
Kennisclips
Hoe doen andere programmeertalen hetzelfde? En een korte zoek-de-fout, om zo kritisch mogelijk naar code te leren kijken.
Hetzelfde idee, andere notatie. In Python zet je de parent tussen haakjes:
Java gebruikt extends
class Paard extends Dier
C++ schrijft
class Paard : public Dier
C# vereist expliciet virtual op de parent én override op de child. In Python is élke methode automatisch overschrijfbaar, zonder keywords:
Ook Java maakt elke (niet-final) methode standaard overschrijfbaar. C# kiest bewust het omgekeerde.
Wat C# base noemt, heet in Python en Java net super:
Onderstaande C#-code wil de poetskost van een frituur correct berekenen. Een Restaurant poetsen kost 1000, een Frituur heeft daarbovenop 500 ontsmetting nodig. Toch komt er een fout uit. Wat loopt er mis?
Opmerking
PoetsAlles in Restaurant staat niet als virtual gemarkeerd, dus de override in Frituur geeft een compileerfout. Zet public virtual void PoetsAlles() in Restaurant, dan mag de child de methode overschrijven.
Een handige samenvattende poster (Opgelet: gemaakt m.b.v. ChatGPT Image Gen 2).