Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Leer Polymorfisme | OOP-Principes
C# Verder dan de Basis

bookPolymorfisme

De term Polymorfisme betekent "voorkomen in verschillende vormen". In de context van objectgeoriënteerd programmeren verwijst polymorfisme naar het vermogen van een klasse om een gemeenschappelijke interface te bieden voor zijn afgeleide klassen, terwijl elke afgeleide klasse specifieke gedragingen kan implementeren voor de overgeërfde methoden.

Normaal gesproken, wanneer een object van een klasse wordt aangemaakt, wordt een variabele aangemaakt om de referentie van dat object vast te houden. Het type van de variabele is meestal de klasse van dat object.

Bijvoorbeeld:

index.cs

index.cs

copy
123
Dog myVar = new Dog(); // or even in case of implicit declaration, 'myVar' will be of type 'Dog' var myVar = new Dog();

Het is echter ook mogelijk om een variabele van een basisklasse aan te maken en daarin een object van een afgeleide klasse op te slaan.

Bijvoorbeeld:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132
using System; class Mammal { public int age; public Mammal(int age) { this.age = age; } } class Dog : Mammal { public string breed; public Dog(int age, string breed) : base(age) { this.breed = breed; } } class ConsoleApp { static void Main() { Mammal example = new Dog(10, "Labrador"); Console.WriteLine(example.age); Console.WriteLine(example.breed); // Error because it's not accessible (read explanation below) } }

Het breed-attribuut van het Dog-object is niet toegankelijk omdat wanneer je het Dog-object opslaat in een Mammal-variabele, het impliciet wordt geconverteerd naar Mammal. Dit betekent dat je alleen toegang hebt tot de attributen en methoden die aanwezig zijn in de Mammal-klasse. Dit betekent niet dat de waarde die is opgeslagen in de breed-klasse verloren gaat; deze is alleen ontoegankelijk en je kunt zeggen dat deze in feite verborgen is.

Je kunt example eenvoudig converteren naar een Dog via expliciete typecasting en het breed-attribuut wordt weer beschikbaar:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940
using System; class Mammal { public int age; public Mammal(int age) { this.age = age; } public void speak() { // Empty for now } } class Dog : Mammal { public string breed; public Dog(int age, string breed) : base(age) { this.breed = breed; } } class ConsoleApp { static void Main() { Mammal example = new Dog(10, "Labrador"); Console.WriteLine(example.age); Dog casted = (Dog)example; Console.WriteLine(casted.breed); } }

Voor methoden is er echter een extra functie genaamd methode-overschrijving, die enigszins lijkt op methode-overbelasting. In dit geval herdefinieer je in feite een methode uit een basisklasse in de afgeleide klasse.

Bijvoorbeeld, je wilt misschien dat Mammal een methode speak() heeft zodat deze Woof! uitvoert als deze wordt aangeroepen vanuit een Dog-object, en Meow! als deze wordt aangeroepen vanuit een Cat-object:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
using System; class Mammal { public void speak() { Console.WriteLine("Mammal Speaks"); } } class Dog : Mammal { public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // The following execute the overriden version of the methods Dog d1 = new Dog(); d1.speak(); Cat c1 = new Cat(); c1.speak(); Mammal m1 = new Mammal(); Mammal m2 = new Cat(); Mammal m3 = new Dog(); // All of these execute the 'Mammal' version of the method m1.speak(); m2.speak(); m3.speak(); } }

De waarschuwingen die je bij deze compilatie krijgt, zijn het gevolg van overlappende namen van methoden in ouder- en kindklassen. In dit geval is er overlap tussen de speak-methoden van de klassen Cat en Mammal, en ook tussen Dog en Mammal, waardoor je twee waarschuwingen krijgt.

Let echter op dat aan het einde m1, m2 en m3 de methode uitvoeren die is gedefinieerd in de klasse Mammal, omdat ze zijn gecast naar Mammal-objecten.

Als je wilt dat de speak-methode zich gedraagt zoals in het oorspronkelijke object, kun je deze eenvoudig omzetten in een virtuele methode. Een virtuele methode is simpelweg een methode die toestaat zichzelf te laten overschrijven vanuit afgeleide klassen, zodat de specifieke implementatie die wordt uitgevoerd tijdens runtime wordt bepaald op basis van het type van het oorspronkelijke object.

Om een methode virtueel te maken, voeg je simpelweg het sleutelwoord virtual toe vóór het returntype:

index.cs

index.cs

copy
1234567
class Mammal { public virtual void speak() { Console.WriteLine("Mammal Speaks"); } }

Om een overschreven implementatie van deze methode te maken, gebruik het sleutelwoord override vóór het retourtype in de implementatie van die nieuwe versie in de afgeleide klasse:

index.cs

index.cs

copy
123456789101112131415
class Dog : Mammal { public override void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { public override void speak() { Console.WriteLine("Meow!"); } }

Laten we nu de twee codefragmenten samenvoegen en bekijken hoe dit het resultaat beïnvloedt:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
using System; class Mammal { public virtual void speak() { Console.WriteLine("Mammal Speaks"); } } class Dog : Mammal { public override void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { public override void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { Mammal m1 = new Mammal(); Mammal m2 = new Cat(); Mammal m3 = new Dog(); m1.speak(); // Since it stores a Mammal() object, it executes the Mammal's implementation m2.speak(); // Output: Meow! m3.speak(); // Output: Woof! // The following behave the same as they did in the previous example: Dog d1 = new Dog(); d1.speak(); Cat c1 = new Cat(); c1.speak(); } }

In de uitvoer zie je dat m2 en m3 de implementatie van de methode van respectievelijk Cat en Dog gebruiken, omdat deze objecten oorspronkelijk Cat en Dog waren. Dit hele proces waarbij methoden worden overschreven zodat ze zich gedragen op basis van hun oorspronkelijke type, wordt polymorfisme genoemd.

Een situatie waarin dit erg nuttig kan zijn, is het kunnen opslaan van objecten van verschillende datatypen in één enkele array of lijst.

Bijvoorbeeld:

index.cs

index.cs

copy
123456789
List<Shape> shapes = new List<Shape>(); shapes.Add(new Rectangle(25, 50)); shapes.Add(new Square(50)); shapes.Add(new Circle(10)); shapes[0].getArea(); // Output: 1250.0f shapes[1].getArea(); // Output: 2500.0f shapes[2].getArea(); // Output: 314.15f

1. Welke twee sleutelwoorden worden gebruikt bij het overschrijven van een methode?

2. Wat is de juiste manier om een methode overschrijfbaar te maken?

question mark

Welke twee sleutelwoorden worden gebruikt bij het overschrijven van een methode?

Select the correct answer

question mark

Wat is de juiste manier om een methode overschrijfbaar te maken?

Select the correct answer

Was alles duidelijk?

Hoe kunnen we het verbeteren?

Bedankt voor je feedback!

Sectie 5. Hoofdstuk 4

Vraag AI

expand

Vraag AI

ChatGPT

Vraag wat u wilt of probeer een van de voorgestelde vragen om onze chat te starten.

Suggested prompts:

Can you explain more about how polymorphism works in arrays or lists?

What are some real-world examples where polymorphism is useful?

Can you show how to implement polymorphism in another programming language?

Awesome!

Completion rate improved to 2.04

bookPolymorfisme

Veeg om het menu te tonen

De term Polymorfisme betekent "voorkomen in verschillende vormen". In de context van objectgeoriënteerd programmeren verwijst polymorfisme naar het vermogen van een klasse om een gemeenschappelijke interface te bieden voor zijn afgeleide klassen, terwijl elke afgeleide klasse specifieke gedragingen kan implementeren voor de overgeërfde methoden.

Normaal gesproken, wanneer een object van een klasse wordt aangemaakt, wordt een variabele aangemaakt om de referentie van dat object vast te houden. Het type van de variabele is meestal de klasse van dat object.

Bijvoorbeeld:

index.cs

index.cs

copy
123
Dog myVar = new Dog(); // or even in case of implicit declaration, 'myVar' will be of type 'Dog' var myVar = new Dog();

Het is echter ook mogelijk om een variabele van een basisklasse aan te maken en daarin een object van een afgeleide klasse op te slaan.

Bijvoorbeeld:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132
using System; class Mammal { public int age; public Mammal(int age) { this.age = age; } } class Dog : Mammal { public string breed; public Dog(int age, string breed) : base(age) { this.breed = breed; } } class ConsoleApp { static void Main() { Mammal example = new Dog(10, "Labrador"); Console.WriteLine(example.age); Console.WriteLine(example.breed); // Error because it's not accessible (read explanation below) } }

Het breed-attribuut van het Dog-object is niet toegankelijk omdat wanneer je het Dog-object opslaat in een Mammal-variabele, het impliciet wordt geconverteerd naar Mammal. Dit betekent dat je alleen toegang hebt tot de attributen en methoden die aanwezig zijn in de Mammal-klasse. Dit betekent niet dat de waarde die is opgeslagen in de breed-klasse verloren gaat; deze is alleen ontoegankelijk en je kunt zeggen dat deze in feite verborgen is.

Je kunt example eenvoudig converteren naar een Dog via expliciete typecasting en het breed-attribuut wordt weer beschikbaar:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940
using System; class Mammal { public int age; public Mammal(int age) { this.age = age; } public void speak() { // Empty for now } } class Dog : Mammal { public string breed; public Dog(int age, string breed) : base(age) { this.breed = breed; } } class ConsoleApp { static void Main() { Mammal example = new Dog(10, "Labrador"); Console.WriteLine(example.age); Dog casted = (Dog)example; Console.WriteLine(casted.breed); } }

Voor methoden is er echter een extra functie genaamd methode-overschrijving, die enigszins lijkt op methode-overbelasting. In dit geval herdefinieer je in feite een methode uit een basisklasse in de afgeleide klasse.

Bijvoorbeeld, je wilt misschien dat Mammal een methode speak() heeft zodat deze Woof! uitvoert als deze wordt aangeroepen vanuit een Dog-object, en Meow! als deze wordt aangeroepen vanuit een Cat-object:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
using System; class Mammal { public void speak() { Console.WriteLine("Mammal Speaks"); } } class Dog : Mammal { public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // The following execute the overriden version of the methods Dog d1 = new Dog(); d1.speak(); Cat c1 = new Cat(); c1.speak(); Mammal m1 = new Mammal(); Mammal m2 = new Cat(); Mammal m3 = new Dog(); // All of these execute the 'Mammal' version of the method m1.speak(); m2.speak(); m3.speak(); } }

De waarschuwingen die je bij deze compilatie krijgt, zijn het gevolg van overlappende namen van methoden in ouder- en kindklassen. In dit geval is er overlap tussen de speak-methoden van de klassen Cat en Mammal, en ook tussen Dog en Mammal, waardoor je twee waarschuwingen krijgt.

Let echter op dat aan het einde m1, m2 en m3 de methode uitvoeren die is gedefinieerd in de klasse Mammal, omdat ze zijn gecast naar Mammal-objecten.

Als je wilt dat de speak-methode zich gedraagt zoals in het oorspronkelijke object, kun je deze eenvoudig omzetten in een virtuele methode. Een virtuele methode is simpelweg een methode die toestaat zichzelf te laten overschrijven vanuit afgeleide klassen, zodat de specifieke implementatie die wordt uitgevoerd tijdens runtime wordt bepaald op basis van het type van het oorspronkelijke object.

Om een methode virtueel te maken, voeg je simpelweg het sleutelwoord virtual toe vóór het returntype:

index.cs

index.cs

copy
1234567
class Mammal { public virtual void speak() { Console.WriteLine("Mammal Speaks"); } }

Om een overschreven implementatie van deze methode te maken, gebruik het sleutelwoord override vóór het retourtype in de implementatie van die nieuwe versie in de afgeleide klasse:

index.cs

index.cs

copy
123456789101112131415
class Dog : Mammal { public override void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { public override void speak() { Console.WriteLine("Meow!"); } }

Laten we nu de twee codefragmenten samenvoegen en bekijken hoe dit het resultaat beïnvloedt:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
using System; class Mammal { public virtual void speak() { Console.WriteLine("Mammal Speaks"); } } class Dog : Mammal { public override void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { public override void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { Mammal m1 = new Mammal(); Mammal m2 = new Cat(); Mammal m3 = new Dog(); m1.speak(); // Since it stores a Mammal() object, it executes the Mammal's implementation m2.speak(); // Output: Meow! m3.speak(); // Output: Woof! // The following behave the same as they did in the previous example: Dog d1 = new Dog(); d1.speak(); Cat c1 = new Cat(); c1.speak(); } }

In de uitvoer zie je dat m2 en m3 de implementatie van de methode van respectievelijk Cat en Dog gebruiken, omdat deze objecten oorspronkelijk Cat en Dog waren. Dit hele proces waarbij methoden worden overschreven zodat ze zich gedragen op basis van hun oorspronkelijke type, wordt polymorfisme genoemd.

Een situatie waarin dit erg nuttig kan zijn, is het kunnen opslaan van objecten van verschillende datatypen in één enkele array of lijst.

Bijvoorbeeld:

index.cs

index.cs

copy
123456789
List<Shape> shapes = new List<Shape>(); shapes.Add(new Rectangle(25, 50)); shapes.Add(new Square(50)); shapes.Add(new Circle(10)); shapes[0].getArea(); // Output: 1250.0f shapes[1].getArea(); // Output: 2500.0f shapes[2].getArea(); // Output: 314.15f

1. Welke twee sleutelwoorden worden gebruikt bij het overschrijven van een methode?

2. Wat is de juiste manier om een methode overschrijfbaar te maken?

question mark

Welke twee sleutelwoorden worden gebruikt bij het overschrijven van een methode?

Select the correct answer

question mark

Wat is de juiste manier om een methode overschrijfbaar te maken?

Select the correct answer

Was alles duidelijk?

Hoe kunnen we het verbeteren?

Bedankt voor je feedback!

Sectie 5. Hoofdstuk 4
some-alt