Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Polymorfismi | OOP-Periaatteet
C# Perusteiden Jälkeen

bookPolymorfismi

Termi polymorfismi tarkoittaa "esiintymistä useissa eri muodoissa". Oliopohjaisessa ohjelmoinnissa polymorfismi viittaa kykyyn, jossa luokka tarjoaa yhteisen rajapinnan johdetuille luokilleen, mutta sallii jokaisen johdetun luokan toteuttaa perittyjen metodien erityiset toiminnot.

Yleensä kun luot olion luokasta, luot muuttujan, joka pitää viitteen tähän olioon. Muuttujan tyyppi on tavallisesti kyseisen olion luokka.

Esimerkiksi:

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();

Voit kuitenkin myös luoda muuttujan, jonka tyyppi on kantaluokka, ja tallentaa siihen johdetun luokan olion.

Esimerkiksi:

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) } }

breed-olion Dog-attribuutti ei ole käytettävissä, koska kun tallennat Dog-olion Mammal-muuttujaan, se muunnetaan implisiittisesti Mammal-tyyppiseksi. Tämä tarkoittaa, että voit käyttää vain niitä attribuutteja ja metodeja, jotka ovat Mammal-luokassa. Tämä ei tarkoita, että breed-luokan arvo olisi kadonnut, vaan se on ainoastaan saavuttamattomissa ja voidaan sanoa, että se on käytännössä piilotettu.

Voit yksinkertaisesti muuntaa example-muuttujan takaisin Dog-tyyppiseksi eksplisiittisellä tyyppimuunnoksella, jolloin breed-attribuutti tulee jälleen saataville:

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); } }

Menetelmille on kuitenkin olemassa lisäominaisuus nimeltä metodin ylikirjoitus (method overriding), joka muistuttaa jossain määrin metodin ylikuormitusta (method overloading). Tässä tapauksessa määrittelet käytännössä uudelleen perusluokan metodin johdetussa luokassa.

Esimerkiksi saatat haluta, että Mammal-luokalla on metodi speak(), joka tuottaa Woof!, jos sitä kutsutaan Dog-oliosta, ja Meow!, jos sitä kutsutaan Cat-oliosta:

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(); } }

Käännöksessä saamasi varoitukset johtuvat siitä, että vanhemman ja lapsiluokan metodeilla on päällekkäiset nimet. Tässä tapauksessa päällekkäisyys on luokkien speak ja Cat Mammal-metodien välillä sekä luokkien Dog ja Mammal speak-metodien välillä, minkä vuoksi saat kaksi varoitusta.

Huomaa kuitenkin, että lopuksi m1, m2 ja m3 suorittavat Mammal-luokassa määritellyn metodin, koska ne on muunnettu Mammal-olioiksi.

Jos haluat, että speak-metodi käyttäytyy alkuperäisen olion mukaisesti, voit yksinkertaisesti muuttaa sen virtuaaliseksi metodiksi. Virtuaalinen metodi on metodi, jonka voi ylikirjoittaa johdetuissa luokissa siten, että toteutus valitaan ajonaikaisesti alkuperäisen olion tyypin perusteella.

Metodin tekemiseksi virtuaaliseksi lisäät vain virtual-avainsanan sen palautustyypin eteen:

index.cs

index.cs

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

Ylikirjoitetun toteutuksen luomiseksi tälle metodille käytetään avainsanaa override ennen palautustyyppiä johdetun luokan uuden version toteutuksessa:

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!"); } }

Yhdistetään nyt kaksi koodiesimerkkiä ja tarkastellaan, miten se vaikuttaa tulosteeseen:

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(); } }

Tulosteessa huomaat, että m2 ja m3 käyttävät Cat- ja Dog-luokkien toteutuksia metodista, koska kyseiset oliot olivat alun perin Cat ja Dog. Tätä koko prosessia, jossa metodeja ylikirjoitetaan niin, että ne käyttäytyvät alkuperäisen tyyppinsä mukaisesti, kutsutaan polymorfismiksi.

Tämä on erityisen hyödyllistä esimerkiksi silloin, kun halutaan tallentaa useiden eri tietotyyppien olioita samaan taulukkoon tai listaan.

Esimerkiksi:

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. Mitkä kaksi avainsanaa käytetään metodin ylikirjoittamisessa?

2. Mikä on oikea tapa tehdä metodista ylikirjoitettava?

question mark

Mitkä kaksi avainsanaa käytetään metodin ylikirjoittamisessa?

Select the correct answer

question mark

Mikä on oikea tapa tehdä metodista ylikirjoitettava?

Select the correct answer

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 5. Luku 4

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

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

bookPolymorfismi

Pyyhkäise näyttääksesi valikon

Termi polymorfismi tarkoittaa "esiintymistä useissa eri muodoissa". Oliopohjaisessa ohjelmoinnissa polymorfismi viittaa kykyyn, jossa luokka tarjoaa yhteisen rajapinnan johdetuille luokilleen, mutta sallii jokaisen johdetun luokan toteuttaa perittyjen metodien erityiset toiminnot.

Yleensä kun luot olion luokasta, luot muuttujan, joka pitää viitteen tähän olioon. Muuttujan tyyppi on tavallisesti kyseisen olion luokka.

Esimerkiksi:

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();

Voit kuitenkin myös luoda muuttujan, jonka tyyppi on kantaluokka, ja tallentaa siihen johdetun luokan olion.

Esimerkiksi:

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) } }

breed-olion Dog-attribuutti ei ole käytettävissä, koska kun tallennat Dog-olion Mammal-muuttujaan, se muunnetaan implisiittisesti Mammal-tyyppiseksi. Tämä tarkoittaa, että voit käyttää vain niitä attribuutteja ja metodeja, jotka ovat Mammal-luokassa. Tämä ei tarkoita, että breed-luokan arvo olisi kadonnut, vaan se on ainoastaan saavuttamattomissa ja voidaan sanoa, että se on käytännössä piilotettu.

Voit yksinkertaisesti muuntaa example-muuttujan takaisin Dog-tyyppiseksi eksplisiittisellä tyyppimuunnoksella, jolloin breed-attribuutti tulee jälleen saataville:

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); } }

Menetelmille on kuitenkin olemassa lisäominaisuus nimeltä metodin ylikirjoitus (method overriding), joka muistuttaa jossain määrin metodin ylikuormitusta (method overloading). Tässä tapauksessa määrittelet käytännössä uudelleen perusluokan metodin johdetussa luokassa.

Esimerkiksi saatat haluta, että Mammal-luokalla on metodi speak(), joka tuottaa Woof!, jos sitä kutsutaan Dog-oliosta, ja Meow!, jos sitä kutsutaan Cat-oliosta:

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(); } }

Käännöksessä saamasi varoitukset johtuvat siitä, että vanhemman ja lapsiluokan metodeilla on päällekkäiset nimet. Tässä tapauksessa päällekkäisyys on luokkien speak ja Cat Mammal-metodien välillä sekä luokkien Dog ja Mammal speak-metodien välillä, minkä vuoksi saat kaksi varoitusta.

Huomaa kuitenkin, että lopuksi m1, m2 ja m3 suorittavat Mammal-luokassa määritellyn metodin, koska ne on muunnettu Mammal-olioiksi.

Jos haluat, että speak-metodi käyttäytyy alkuperäisen olion mukaisesti, voit yksinkertaisesti muuttaa sen virtuaaliseksi metodiksi. Virtuaalinen metodi on metodi, jonka voi ylikirjoittaa johdetuissa luokissa siten, että toteutus valitaan ajonaikaisesti alkuperäisen olion tyypin perusteella.

Metodin tekemiseksi virtuaaliseksi lisäät vain virtual-avainsanan sen palautustyypin eteen:

index.cs

index.cs

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

Ylikirjoitetun toteutuksen luomiseksi tälle metodille käytetään avainsanaa override ennen palautustyyppiä johdetun luokan uuden version toteutuksessa:

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!"); } }

Yhdistetään nyt kaksi koodiesimerkkiä ja tarkastellaan, miten se vaikuttaa tulosteeseen:

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(); } }

Tulosteessa huomaat, että m2 ja m3 käyttävät Cat- ja Dog-luokkien toteutuksia metodista, koska kyseiset oliot olivat alun perin Cat ja Dog. Tätä koko prosessia, jossa metodeja ylikirjoitetaan niin, että ne käyttäytyvät alkuperäisen tyyppinsä mukaisesti, kutsutaan polymorfismiksi.

Tämä on erityisen hyödyllistä esimerkiksi silloin, kun halutaan tallentaa useiden eri tietotyyppien olioita samaan taulukkoon tai listaan.

Esimerkiksi:

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. Mitkä kaksi avainsanaa käytetään metodin ylikirjoittamisessa?

2. Mikä on oikea tapa tehdä metodista ylikirjoitettava?

question mark

Mitkä kaksi avainsanaa käytetään metodin ylikirjoittamisessa?

Select the correct answer

question mark

Mikä on oikea tapa tehdä metodista ylikirjoitettava?

Select the correct answer

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 5. Luku 4
some-alt