Polymorfism
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
123Dog 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
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) } }
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
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); } }
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
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(); } }
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
1234567class 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
123456789101112131415class 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
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(); } }
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
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. Vilka två nyckelord används vid metodöverskuggning?
2. Vad är det korrekta sättet att göra en metod överskuggbar?
Tack för dina kommentarer!
Fråga AI
Fråga AI
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
Polymorfism
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
123Dog 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
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) } }
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
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); } }
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
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(); } }
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
1234567class 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
123456789101112131415class 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
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(); } }
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
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. Vilka två nyckelord används vid metodöverskuggning?
2. Vad är det korrekta sättet att göra en metod överskuggbar?
Tack för dina kommentarer!