Polymorfisme
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
123Dog 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
1234567891011121314151617181920212223242526272829303132using 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
12345678910111213141516171819202122232425262728293031323334353637383940using 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
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647using 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
1234567class 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
123456789101112131415class 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
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647using 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
123456789List<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?
Bedankt voor je feedback!
Vraag AI
Vraag AI
Vraag wat u wilt of probeer een van de voorgestelde vragen om onze chat te starten.
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
Polymorfisme
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
123Dog 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
1234567891011121314151617181920212223242526272829303132using 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
12345678910111213141516171819202122232425262728293031323334353637383940using 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
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647using 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
1234567class 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
123456789101112131415class 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
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647using 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
123456789List<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?
Bedankt voor je feedback!