Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lära Polymorfism | OOP-principer
C# Bortom Grunderna

bookPolymorfism

Termen Polymorfism betyder "förekommer i flera olika former". Inom objektorienterad programmering syftar polymorfism på förmågan hos en klass att tillhandahålla ett gemensamt gränssnitt för sina underklasser, samtidigt som varje underklass kan implementera specifika beteenden för de ärvda metoderna.

Normalt när du skapar ett objekt av en klass, skapar du en variabel för att hålla referensen till det objektet. Och typen av variabeln är vanligtvis klassens typ för det objektet.

Till exempel:

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

Du kan dock även skapa en variabel av en basklass och lagra ett objekt av en underklass i den.

Till exempel:

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

Attributet breed för Dog-objektet är inte tillgängligt eftersom när du lagrar Dog-objektet i en Mammal-variabel, det implicit konverteras till Mammal. Det innebär att du endast kan komma åt de attribut och metoder som finns i klassen Mammal. Det betyder inte att värdet som lagras i klassen breed är förlorat, det är bara otillgängligt och kan sägas vara dolt.

Du kan enkelt konvertera example till en Dog genom explicit typomvandling och attributet breed blir tillgängligt igen:

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

För metoder finns det dock en ytterligare funktion som kallas metodöverskuggning (method overriding), vilket påminner något om metodöverlagring (method overloading). I detta fall omdefinierar du i princip en metod från en basklass i den ärvda klassen.

Till exempel kan du vilja att Mammal har en metod speak() så att den skriver ut Woof! om den anropas från ett Dog-objekt, och Meow! om den anropas från ett Cat-objekt:

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

Varningarna du får vid denna kompilering beror på överlappande namn på metoder i föräldra- och barnklasser. I detta fall finns det en överlappning mellan speak-metoderna i klasserna Cat och Mammal, samt mellan Dog och Mammal, vilket är anledningen till att du får två varningar.

Observera dock att i slutet så exekverar m1, m2 och m3 metoden som är definierad i klassen Mammal, eftersom de är typomvandlade till Mammal-objekt.

Om du vill att speak-metoden ska bete sig som i sitt ursprungliga objekt kan du helt enkelt göra den till en virtuell metod. En virtuell metod är en metod som tillåter dig att överskugga sig själv från ärvda klasser på ett sådant sätt att den specifika implementationen som körs bestäms vid körtid baserat på typen av det ursprungliga objektet.

För att göra en metod virtuell lägger du helt enkelt till nyckelordet virtual före dess returtyp:

index.cs

index.cs

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

För att skapa en överskuggad implementation av denna metod, använd nyckelordet override före returtypen i den härledda klassens implementation av den nya versionen:

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

Låt oss nu sammanfoga de två kodsnuttarna och se hur det påverkar utdata:

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

Du ser att i utdata använder m2 och m3 Cat och Dog-klassernas implementation av metoden eftersom dessa objekt ursprungligen var Cat och Dog. Denna process där metoder överskuggas så att de beter sig utifrån sin ursprungliga typ kallas polymorfism.

En situation där detta kan vara mycket användbart är möjligheten att lagra objekt av flera olika datatyper i en enda array eller lista.

Till exempel:

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. Vilka två nyckelord används vid metodöverskuggning?

2. Vad är det korrekta sättet att göra en metod överskuggbar?

question mark

Vilka två nyckelord används vid metodöverskuggning?

Select the correct answer

question mark

Vad är det korrekta sättet att göra en metod överskuggbar?

Select the correct answer

Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 5. Kapitel 4

Fråga AI

expand

Fråga AI

ChatGPT

Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal

Awesome!

Completion rate improved to 2.04

bookPolymorfism

Svep för att visa menyn

Termen Polymorfism betyder "förekommer i flera olika former". Inom objektorienterad programmering syftar polymorfism på förmågan hos en klass att tillhandahålla ett gemensamt gränssnitt för sina underklasser, samtidigt som varje underklass kan implementera specifika beteenden för de ärvda metoderna.

Normalt när du skapar ett objekt av en klass, skapar du en variabel för att hålla referensen till det objektet. Och typen av variabeln är vanligtvis klassens typ för det objektet.

Till exempel:

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

Du kan dock även skapa en variabel av en basklass och lagra ett objekt av en underklass i den.

Till exempel:

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

Attributet breed för Dog-objektet är inte tillgängligt eftersom när du lagrar Dog-objektet i en Mammal-variabel, det implicit konverteras till Mammal. Det innebär att du endast kan komma åt de attribut och metoder som finns i klassen Mammal. Det betyder inte att värdet som lagras i klassen breed är förlorat, det är bara otillgängligt och kan sägas vara dolt.

Du kan enkelt konvertera example till en Dog genom explicit typomvandling och attributet breed blir tillgängligt igen:

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

För metoder finns det dock en ytterligare funktion som kallas metodöverskuggning (method overriding), vilket påminner något om metodöverlagring (method overloading). I detta fall omdefinierar du i princip en metod från en basklass i den ärvda klassen.

Till exempel kan du vilja att Mammal har en metod speak() så att den skriver ut Woof! om den anropas från ett Dog-objekt, och Meow! om den anropas från ett Cat-objekt:

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

Varningarna du får vid denna kompilering beror på överlappande namn på metoder i föräldra- och barnklasser. I detta fall finns det en överlappning mellan speak-metoderna i klasserna Cat och Mammal, samt mellan Dog och Mammal, vilket är anledningen till att du får två varningar.

Observera dock att i slutet så exekverar m1, m2 och m3 metoden som är definierad i klassen Mammal, eftersom de är typomvandlade till Mammal-objekt.

Om du vill att speak-metoden ska bete sig som i sitt ursprungliga objekt kan du helt enkelt göra den till en virtuell metod. En virtuell metod är en metod som tillåter dig att överskugga sig själv från ärvda klasser på ett sådant sätt att den specifika implementationen som körs bestäms vid körtid baserat på typen av det ursprungliga objektet.

För att göra en metod virtuell lägger du helt enkelt till nyckelordet virtual före dess returtyp:

index.cs

index.cs

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

För att skapa en överskuggad implementation av denna metod, använd nyckelordet override före returtypen i den härledda klassens implementation av den nya versionen:

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

Låt oss nu sammanfoga de två kodsnuttarna och se hur det påverkar utdata:

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

Du ser att i utdata använder m2 och m3 Cat och Dog-klassernas implementation av metoden eftersom dessa objekt ursprungligen var Cat och Dog. Denna process där metoder överskuggas så att de beter sig utifrån sin ursprungliga typ kallas polymorfism.

En situation där detta kan vara mycket användbart är möjligheten att lagra objekt av flera olika datatyper i en enda array eller lista.

Till exempel:

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. Vilka två nyckelord används vid metodöverskuggning?

2. Vad är det korrekta sättet att göra en metod överskuggbar?

question mark

Vilka två nyckelord används vid metodöverskuggning?

Select the correct answer

question mark

Vad är det korrekta sättet att göra en metod överskuggbar?

Select the correct answer

Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 5. Kapitel 4
some-alt