Zie Scherp Scherper - Hoofdstuk 13
Na dit hoofdstuk kan je:
:-notatieprotected-keyword en de regels rond private toepassenbase())virtual en overridebaseWe deden al abstractie en encapsulatie. Nu: inheritance.
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:
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.
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:
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 overridenoverride moet identiek zijn aan die van de parentWaarschuwing
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 beschrijvingTreasureRoom: houdt bij hoeveel goud er ligtTrapRoom: doet schadeBossRoom: monsterkamer met veel meer levensVampireRoom: enkel ’s nachts actiefTip
Elke kamer overridet Describe(). Omdat MonsterRoom een Room is, past hij overal waar een Room past (polymorfisme, hoofdstuk 16). Startproject: RoomWalkerDemo2025.
private blijft afgeschermd; protected opent het voor childrenbase() kies je de juiste parent-constructorvirtual + override laten een child de werking aanpassenbase hergebruik je de parent-implementatie binnen een overrideTip
Volgende halte: gevorderde overerving: System.Object, abstract en eigen exceptions.
Kennisclips
Dezelfde concepten uit dit hoofdstuk, maar dan in andere talen. Handig om later code in Python of JavaScript te leren lezen.
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:
Een handige samenvattende poster (Opgelet: gemaakt m.b.v. ChatGPT Image Gen 2).