arrow-left

All pages
gitbookPowered by GitBook
1 of 6

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Virtual en override

hashtag
Virtual en Override

Soms willen we aangeven dat de implementatie (code) van een property of methode in een parent-klasse door child-klassen mag aangepast worden. Dit geven we aan met het virtual keyword:

Stel dat we 2 objecten aanmaken en laten vliegen:

Vliegtuig f1 = new Vliegtuig();
Raket spaceX1 = new Raket();
f1.Vlieg();
spaceX1.Vlieg();

De uitvoer zal dan zijn:

Een raket is een vliegtuig, toch vliegt het anders. We willen dus de methode Vlieg anders uitvoeren voor een raket. Daar hebben we override voor nodig. Door override voor een methode in de child-klasse te plaatsen zeggen we "gebruik deze implementatie en niet die van de parent klasse." Je kan enkel overriden indien de respectievelijke methode of property in de parent-klasse als virtual werd aangeduid

De uitvoer van volgende code zal nu anders zijn:

Uitvoer:

hashtag
Properties overriden

Ook properties kan je virtual instellen en override'n.

Opgelet: Visual Studio gebruikt Expression Body Member syntax (herkenbaar aan de =>) om properties te overriden. Deze syntax kennen we niet (lees er gerust meer over ). Je schrijft dus best manueel de override van properties

Stel dat je volgende klasse hebt:

We maken nu een meer luxueuze auto die een lichtje heeft dat aangaat wanneer de benzine-tank vol genoeg is, dit kan via override.

hashtag
Kennisclip

class Vliegtuig
{
   public virtual void Vlieg()
   {
      Console.WriteLine("Het vliegtuig vliegt rustig door de wolken.");
   }
}

class Raket: Vliegtuig
{
}
Het vliegtuig vliegt rustig door de wolken.
Het vliegtuig vliegt rustig door de wolken.

Base keyword

Het base keyword laat ons toe om bij een overriden methode of property in de child-klasse toch te verplichten om de parent-implementatie toe te passen.

Stel dat we volgende 2 klassen hebben:

class Restaurant
{
     protected int kosten=0;
     public virtual void PoetsAlles()
     {
           kosten+=1000;
     }
}

class Frituur:Restaurant
{
     public override void PoetsAlles()
     {
           kosten+= (1000 + 500);
     }

}

Het poetsen van een Frituur is duurder (1000 basis + 500 voor ontsmetting) dan een gewoon restaurant. Als we echter later beslissen dat de basisprijs (in Restaurant) moet veranderen dan moet je ook in alle child-klassen doen. Base lost dit voor ons. De Frituur-klasse herschrijven we naar:

class Frituur:Restaurant
{
     public override void PoetsAlles()
     {
           base.PoetsAlles(); //eerste basiskost wordt opgeteld
           kosten+=500;  //kosten eigen aan frituur worden bijgeteld.
     }

}
hier
Virtual en overridearrow-up-right

Constructors bij overerving

hashtag
Constructors bij overerving

Wanneer je een object instantiëert van een child-klasse dan gebeuren er meerdere zaken na elkaar, in volgende volgorde:

  • Eerst wordt de constructor aangeroepen van de basis-klasse: dus steeds eerst die van System.Object

  • Gevolgd door de constructors van alle parent-klassen

  • Finaal de constructor van de klasse zelf.

Volgende voorbeeld toont dit in actie:

Indien je vervolgens een object aanmaakt van het type Medic:

Dan zal zien we de volgorde van constructor-aanroep op het scherm:

Er wordt dus verondersteld in dit geval dat er een default constructor in de basis-klasse aanwezig is.

hashtag
Overloaded constructors

Indien je klasse Soldier een overloaded constructor heeft, dan geeft deze niet automatisch een default constructor. Volgende code zou dus een probleem geven indien je een Medic wilt aanmaken via new Medic():

Wat je namelijk niet ziet bij child-klassen en hun constructors is dat er eigenlijk een impliciete call naar de basis-constructor wordt gedaan. Bij alle constructors staat eigenlijk :base() wat je ook zelf kunt schrijven:

base() achter de constructor zegt dus eigenlijk 'roep de constructor van de parent-klasse aan. Je mag hier echter ook parameters meegeven en de compiler zal dan zoeken naar een constructor in de basis-klasse die deze volgorde van parameters kan accepteren.

We zien hier dus hoe we ervoor moeten zorgen dat we terug Medics via new Medic() kunnen aanroepen zonder dat we de constructor(s) van Soldier moeten aanpassen:

De medics zullen de canShoot dus steeds op true zetten. Uiteraard wil je misschien dit kunnen meegeven bij het aanmaken van een object zoals new Medic(false), dit vereist dat je dus een overloaded constructor in Medic aanmaakt, die op zijn beurt de overloaded constructor van Soldier aanroept. Je schrijft dan een overloaded constructor in Medic bij:

Uiteraard mag je ook de default constructor aanroepen vanuit de child-constructor, alle combinaties zijn mogelijk (zolang de constructor in kwestie maar bestaat in de parent-klasse).

hashtag
Kennisclip

*

Overerving intro

hashtag
Overerving

Overerving (inheritance) laat ons toe om klassen te specialiseren vanuit een reeds bestaande basisklasse. Wanneer we een klasse van een andere klasse overerven dan zeggen we dat deze nieuwe klasse een child-klasse of sub-klasse is van de bestaande parent-klasse of super-klasse.

De child-klasse kan alles wat de parent-klasse kan, maar de nieuwe klasse kan nu ook extra specialisatie code krijgen.

hashtag
Is-een relatie

Wanneer twee klassen met behulp van een "x is een y"-relatie kunnen beschreven worden dan weet je dat overerving mogelijk.

  • Een paard is een dier (paard = child-klasse, dier= parent-klasse)

  • Een tulp is een plant

circle-exclamation

Opgelet: wanneer we "x heeft een y" zeggen gaat het niet over overerving, maar over .

hashtag
Inheritance in CS

Overving duid je aan met behulp van het dubbele punt(:) bij de klassedefinitie:

Een voorbeeld:

Objecten van het type Dier kunnen enkel de Eet-methode aanroepen. Objecten van het type Paard kunnen de Eet-methode aanroepen én ze hebben ook een property KanHinnikken:

hashtag
Multiple inheritance

In C# is het niet mogelijk om een klasse van meer dan een parent-klasse te laten overerven (zogenaamde multiple inheritance), wat wel mogelijk is in sommige andere object georiënteerde talen.

hashtag
Transitive

Overerving in C# is transitief, dit wil zeggen dat de child-klasse niet alleen overerft van haar ouderklasse, maar ook van grootouderklassen enzovoort. Je zou bijvoorbeeld een subklasse Pony van de klasse Paard kunnen toevoegen. Een Pony is een Paard en een Paard is een Dier, dus een Pony is ook een Dier en heeft bijvoorbeeld een methode Eet.

hashtag
Protected

Ook al heeft een subklasse alle onderdeeltjes van een ouderklasse, hou er rekening mee dat private variabelen en methoden van de parent-klasse NIET rechtsreeks aanroepbaar zijn in de child-klasse. Private betekent namelijk: "enkel toegankelijk binnenin deze klasse". Private geeft aan dat het element enkel in de klasse zichtbaar is:

Een Paard heeft nog wel een leeftijd, maar binnenin de code voor de klasse Paard kan je de leeftijd niet zomaar opvragen of aanpassen.

Je kan dit oplossen door de protected access modifier ipv private te gebruiken. Met protected geef je aan dat het element enkel zichtbaar is binnen de klasse en binnen child-klassen:

hashtag
Sealed

Soms wil je niet dat van een klasse nog nieuwe klasse kunnen overgeërfd worden. Je lost dit op door het keyword sealed voor de klasse te zetten:

Als je later dan dit probeert:

zal dit resulteren in een foutoodschap, namelijk cannot derive from sealed type 'DoNotInheritMe'.

hashtag
Kennisclip

Oefeningen

hashtag
Een bestaande klasse uitbreiden via overerving

hashtag
Leerdoelen

  • overerving van bestaande klassen laten zien

  • toegang tot properties en methodes demonstreren

hashtag
Functionele analyse

Maak een nieuwe klasse, WorkingStudent. Een werkstudent verschilt van een student omdat hij soms moet gaan werken en omdat hij een bepaald aantal werkuren per week moet presteren.

hashtag
Technische analyse

Deze klasse erft over van de klasse Student die je voor het eerst hebt gebruikt in hoofdstuk 8.

Bovenop alle eigenschappen / methoden van Student heeft WorkingStudent:

  • een methode HasWorkToday() die willekeurig true of false teruggeeft. Er is geen methode NextBool in de klasse random, maar je kan een willekeurig getal tussen 0 en 1 genereren en de uitkomst vertalen in een boolean.

  • een property WorkHours die een aantal gepresteerde uren bijhoudt (als byte

Voeg een statische methode DemonstrateWorkingStudent() toe aan je klasse voor deze les. Deze methode doet volgende zaken:

  • ze maakt met de default constructor één gewone student aan (de properties mag je invullen zoals je zelf wil, maar vul ze wel in)

  • ze maakt met de default constructor één werkstudent aan (de properties mag je invullen zoals je zelf wil, maar vul ze wel in)

  • ze plaatst beide in een List<Student>

hashtag
Klassen met aangepaste constructor maken

hashtag
Functionele analyse

We schrijven een applicatie die een lijst van af te handelen taken bijhoudt. Er zijn twee soorten taken: éénmalige taken en terugkerende taken. Elke taak heeft een beschrijving, maar terugkerende taken hebben ook een bepaalde hoeveelheid tijd waarna ze herhaald moeten worden.

hashtag
Technische analyse

  • Maak een klasse Task met een property Description en een constructor die een waarde voor deze beschrijving verwacht (een string).

    • Wanneer deze constructor wordt opgeroepen, wordt volgende tekst getoond: "Taak is aangemaakt." Je vult hier zelf de beschrijving van de taak in.

hashtag
Voorbeeldinteractie

hashtag
Oefening: H12-ziekenhuis

hashtag
Leerdoelen

  • werken met methodes

  • methodes overschrijfbaar maken

  • code specifieker maken met behulp van subklassen

hashtag
Functionele analyse

Dit programma berekent de doktersrekening van een patiënt, op basis van een basisbedrag (€50) en een extra kost (€20/uur). In het geval van een verzekerde patiënt worden de kosten met 10% verlaagd.

hashtag
Technische analyse

  • Schrijf twee klassen: Patient en InsuredPatient

  • Beide hebben als properties een naam (een string) en een verblijfsduur (een uint)

hashtag
voorbeeldinteractie

circle-info

Zie je geen €-symbool in je output? In het eerste semester hebben we gezien hoe je het gebruik van Unicode activeert.

hashtag
Testscenario's

  • Test ook uit met een verblijf van 1 uur.

  • Test ook uit met een verblijf van 0 uur.

  • Test ook uit met de patiënten beschreven in de voorbeeldinteractie.

hashtag
Oefening: dynamic dispatch

hashtag
Leerdoelen

  • herbruik code ouderklasse

  • virtual, override, base

hashtag
Functionele analyse

Onze rapporten van studenten missen belangrijke informatie. We willen te zien krijgen wie het statuut van werkstudent heeft.

hashtag
Technische analyse

Pas je klassen Student en WorkingStudent aan, zodat de bestaande methode ShowOverview een uitgebreider overzicht toont voor werkstudenten (voor gewone studenten blijft het ongewijzigd). Dit heeft dan de vorm:

De laatste twee regels komen bovenop de info die je eerder al toonde. Maak gebruik van base zodat je niet de volledige implementatie opnieuw hoeft te schrijven. Pas nu je methode DemonstrateWorkingStudent aan zodat niet de naam van elke student in de lijst wordt getoond, maar zodat zijn volledig rapport wordt getoond.

class Raket:Vliegtuig
{
   public override void Vlieg()
   {
      Console.WriteLine("De raket verdwijnt in de ruimte.");
   }     
}
Vliegtuig f1= new Vliegtuig();
Raket spaceX1= new Raket();
f1.Vlieg();
spaceX1.Vlieg();
Het vliegtuig vliegt rustig door de wolken.
De raket verdwijnt in de ruimte.
    class Auto
    {
        virtual public int Fuel { get; set; }
    }
class LuxeAuto : Auto
{
   public bool HeeftVolleTank { get; set; }

   public override int Fuel
   {
      get { return base.Fuel; }
      set
      {
            if (value > 100)
            {
               HeeftVolleTank = true;
            }
            base.Fuel = value;
      }
   }
}

H12: Overerving

). Deze staat waarden tussen 1 en 20 toe. Lagere of hogere waarden worden automatisch aangepast (naar 1 of 20 naargelang of de waarde lager of hoger is).
  • de defaultwaarde van deze property is 10

ze doorloopt met een foreach-lus de lijst en toont via Console.WriteLine de naam van elke student

  • je moet deze methode kunnen opstarten vanuit je keuzemenu voor dit onderwerp

  • Maak een subklasse RecurringTask van Task. Deze heeft een constructor die twee zaken verwacht: een beschrijving (nog steeds een string) en een aantal dagen (een byte).

    • Wanneer deze constructor wordt opgeroepen, wordt de tekst voor een gewone taak getoond. Daaronder wordt getoond: "Deze taak moet om de dagen herhaald worden."

  • Voeg een statische methode DemonstrateTasks() toe aan je klasse voor deze les. Deze methode maakt eerst een ArrayList van taken aan en herhaalt daarna volgende stappen tot de gebruiker aangeeft dat hij klaar is:

    • ze toont drie opties: een taak aanmaken, een terugkerende taak aanmaken of stoppen

    • indien de gebruiker vraagt een taak aan te maken, vraagt ze een beschrijving, maakt ze de taak en voegt ze deze toe aan de lijst

    • indien de gebruiker vraagt een terugkerende taak aan te maken, vraagt ze een beschrijving en een aantal dagen, maakt ze de terugkerende taak en voegt ze deze toe aan de lijst

    • indien de gebruiker wenst te stoppen, eindigt ze zonder resultaat

    • je moet deze methode kunnen opstarten vanuit je keuzemenu voor dit onderwerp

  • Beide hebben één constructor die de naam en verblijfsduur als parameter hebben
  • Beide hebben een methode ShowCost die een boodschap op het scherm print die zegt hoe veel die patiënt moet betalen

    • Omdat de kost anders bepaald wordt voor een gewone patiënt dan voor een verzekerde patiënt, moet je deze methode overschrijfbaar maken in Patient en moet je ze overschrijven in InsuredPatient. De kost wordt getoond met twee cijfers na de komma.

  • Voeg een statische methode DemonstratePatients() toe aan je klasse voor deze les. Deze methode maakt patiënten aan en roept hun methode ShowCost op, zodat onderstaande voorbeeldinteractie te zien is

  • Wat wil je doen?
    1. een taak maken
    2. een terugkerende taak maken
    3. stoppen
    > 1
    Beschrijving van de taak?
    > TV ophangen
    Taak TV ophangen is aangemaakt.
    Wat wil je doen?
    1. een taak maken
    2. een terugkerende taak maken
    3. stoppen
    > 2
    Beschrijving van de taak?
    > Vuilzakken buiten zetten
    Aantal dagen tussen herhaling?
    > 7
    Taak Vuilzakken buiten zetten is aangemaakt.
    Deze taak moet om de 7 dagen herhaald worden.
    Wat wil je doen?
    1. een taak maken
    2. een terugkerende taak maken
    3. stoppen
    > 3
    Vincent, een gewone patiënt die 12 uur in het ziekenhuis gelegen heeft, betaalt €290.00.
    Tim, een verzekerde patiënt die 12 uur in het ziekenhuis gelegen heeft, betaalt €261.00.
    Joske Vermeulen, 21 jaar
    Klas: EA2
    
    Cijferrapport:
    **********
    Communicatie:             12
    Programming Principles:   15
    Web Technology:           13
    Gemiddelde:               13.3
    Statuut: werkstudent
    Aantal werkuren per week: 10
    Constructors bij overervingarrow-up-right
    compositiearrow-up-right
    Overerving overzichtarrow-up-right
    class Soldier
    {
       public Soldier() {Console.WriteLine("Soldier reporting in");}
    }
    
    class Medic:Soldier
    {
       public Medic(){Console.WriteLine("Who needs healing?");}
    }
    Medic RexGregor= new Medic();
    Soldier reporting in
    Who needs healing?
    class Soldier
    {
       public Soldier(bool canShoot) {//...Do stuff  }
    }
    
    class Medic:Soldier
    {
       public Medic(){Console.WriteLine("Who needs healing?");}
    }
    class Medic:Soldier
    {
       public Medic(): base()
       {Console.WriteLine("Who needs healing?");}
    }
    class Soldier
    {
       public Soldier(bool canShoot) {//...Do stuff  }
    }
    
    class Medic:Soldier
    {
       public Medic():base(true)
        {Console.WriteLine("Who needs healing?");}
    }
    class Soldier
    {
       public Soldier(bool canShoot) {//...Do stuff  }
    }
    
    class Medic:Soldier
    {
       public Medic(bool canSh): base(canSh)
       {} 
    
       public Medic():base(true)  //Default
        {Console.WriteLine("Who needs healing?");}
    }
    class Paard: Dier
    {
       public bool KanHinnikken{get;set;}
    }
    
    class Dier
    {
       public void Eet()
       {
        //...
       }
    }
    Dier aDier= new Dier();
    Paard bPaard= new Paard();
    aDier.Eet();
    bPaard.Eet();
    bPaard.KanHinnikken=false;
    aDier.KanHinnikken=false; //!!! zal niet werken!
    class Paard: Dier
    {
       public void MaakOuder()
       {
          leeftijd++; //  !!! dit zal error geven!
       }
    }
    
    class Dier
    {
       private int leeftijd;
    }
    class Paard: Dier
    {
       public void MaakOuder()
       {
          leeftijd++; //  werkt nu wel
       }
    }
    
    class Dier
    {
       protected int leeftijd;
    }
    sealed class DoNotInheritMe
    {
       //...
    }
    class ChildClass:DoNotInheritMe
    {
       //...
    }