Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Polymorfi | OOP-Principper
C# Ud Over Det Grundlæggende

bookPolymorfi

Begrebet Polymorfi betyder "forekommer i flere forskellige former". I objektorienteret programmering refererer polymorfi til en klasses evne til at tilbyde et fælles interface for sine afledte klasser, samtidig med at hver afledt klasse kan implementere specifikke funktionaliteter for de nedarvede metoder.

Normalt, når der oprettes et objekt af en klasse, oprettes en variabel til at holde referencen til dette objekt. Typen af variablen er som regel klassens type for det pågældende objekt.

For eksempel:

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

Det er dog også muligt at oprette en variabel af en basisklasse og gemme et objekt af en afledt klasse i den.

For eksempel:

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

Attributten breed for Dog-objektet er ikke tilgængelig, fordi når du gemmer Dog-objektet i en Mammal-variabel, bliver det implicit konverteret til Mammal. Det betyder, at du kun kan få adgang til de attributter og metoder, der findes i Mammal-klassen. Det betyder ikke, at værdien gemt i breed-klassen går tabt, den er blot utilgængelig og kan siges at være skjult.

Du kan nemt konvertere example til en Dog via eksplicit typecasting, og attributten breed vil igen være tilgængelig:

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

For metoder findes der dog en ekstra funktion kaldet metodeoverskrivning, som minder om metodeoverbelastning. Her omdefineres en metode fra en basisklasse i den afledte klasse.

For eksempel kan det ønskes, at Mammal har en metode speak(), så den returnerer Woof!, hvis den kaldes fra et Dog-objekt, og Meow!, hvis den kaldes fra et 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(); } }

Advarslerne ved denne kompilering skyldes overlappende navne på metoder i forældre- og barneklasser. Her er der overlap mellem speak-metoderne i Cat- og Mammal-klasserne samt mellem Dog- og Mammal-klassen, hvilket giver to advarsler.

Bemærk dog til sidst, hvordan m1, m2 og m3 udfører metoden defineret i Mammal-klassen, da de er castet til Mammal-objekter.

Hvis det ønskes, at speak-metoden skal opføre sig som i det oprindelige objekt, kan den blot konverteres til en virtuel metode. En virtuel metode er en metode, der tillader overskrivning fra afledte klasser, således at den specifikke implementering, der udføres, bestemmes ved kørselstidspunktet baseret på typen af det oprindelige objekt.

For at gøre en metode virtuel tilføjes blot nøgleordet virtual før dens returtype:

index.cs

index.cs

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

For at lave en overskrevet implementering af denne metode, anvendes nøgleordet override før returtypen i den afledte klasses implementering af den nye version:

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

Lad os nu samle de to kodeeksempler og se, hvordan det påvirker outputtet:

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 kan se, at i outputtet bruger m2 og m3 henholdsvis Cat og Dog's implementering af metoden, fordi disse objekter oprindeligt var Cat og Dog. Denne proces, hvor metoder overskrives, så de opfører sig i henhold til deres oprindelige type, kaldes polymorfi.

En situation, hvor dette kan være meget nyttigt, er muligheden for at gemme objekter af flere forskellige datatyper i et enkelt array eller en liste.

For eksempel:

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. Hvilke to nøgleord bruges ved metodeoverskrivning?

2. Hvad er den korrekte måde at gøre en metode overskrivelig på?

question mark

Hvilke to nøgleord bruges ved metodeoverskrivning?

Select the correct answer

question mark

Hvad er den korrekte måde at gøre en metode overskrivelig på?

Select the correct answer

Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 5. Kapitel 4

Spørg AI

expand

Spørg AI

ChatGPT

Spørg om hvad som helst eller prøv et af de foreslåede spørgsmål for at starte vores chat

Awesome!

Completion rate improved to 2.04

bookPolymorfi

Stryg for at vise menuen

Begrebet Polymorfi betyder "forekommer i flere forskellige former". I objektorienteret programmering refererer polymorfi til en klasses evne til at tilbyde et fælles interface for sine afledte klasser, samtidig med at hver afledt klasse kan implementere specifikke funktionaliteter for de nedarvede metoder.

Normalt, når der oprettes et objekt af en klasse, oprettes en variabel til at holde referencen til dette objekt. Typen af variablen er som regel klassens type for det pågældende objekt.

For eksempel:

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

Det er dog også muligt at oprette en variabel af en basisklasse og gemme et objekt af en afledt klasse i den.

For eksempel:

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

Attributten breed for Dog-objektet er ikke tilgængelig, fordi når du gemmer Dog-objektet i en Mammal-variabel, bliver det implicit konverteret til Mammal. Det betyder, at du kun kan få adgang til de attributter og metoder, der findes i Mammal-klassen. Det betyder ikke, at værdien gemt i breed-klassen går tabt, den er blot utilgængelig og kan siges at være skjult.

Du kan nemt konvertere example til en Dog via eksplicit typecasting, og attributten breed vil igen være tilgængelig:

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

For metoder findes der dog en ekstra funktion kaldet metodeoverskrivning, som minder om metodeoverbelastning. Her omdefineres en metode fra en basisklasse i den afledte klasse.

For eksempel kan det ønskes, at Mammal har en metode speak(), så den returnerer Woof!, hvis den kaldes fra et Dog-objekt, og Meow!, hvis den kaldes fra et 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(); } }

Advarslerne ved denne kompilering skyldes overlappende navne på metoder i forældre- og barneklasser. Her er der overlap mellem speak-metoderne i Cat- og Mammal-klasserne samt mellem Dog- og Mammal-klassen, hvilket giver to advarsler.

Bemærk dog til sidst, hvordan m1, m2 og m3 udfører metoden defineret i Mammal-klassen, da de er castet til Mammal-objekter.

Hvis det ønskes, at speak-metoden skal opføre sig som i det oprindelige objekt, kan den blot konverteres til en virtuel metode. En virtuel metode er en metode, der tillader overskrivning fra afledte klasser, således at den specifikke implementering, der udføres, bestemmes ved kørselstidspunktet baseret på typen af det oprindelige objekt.

For at gøre en metode virtuel tilføjes blot nøgleordet virtual før dens returtype:

index.cs

index.cs

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

For at lave en overskrevet implementering af denne metode, anvendes nøgleordet override før returtypen i den afledte klasses implementering af den nye version:

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

Lad os nu samle de to kodeeksempler og se, hvordan det påvirker outputtet:

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 kan se, at i outputtet bruger m2 og m3 henholdsvis Cat og Dog's implementering af metoden, fordi disse objekter oprindeligt var Cat og Dog. Denne proces, hvor metoder overskrives, så de opfører sig i henhold til deres oprindelige type, kaldes polymorfi.

En situation, hvor dette kan være meget nyttigt, er muligheden for at gemme objekter af flere forskellige datatyper i et enkelt array eller en liste.

For eksempel:

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. Hvilke to nøgleord bruges ved metodeoverskrivning?

2. Hvad er den korrekte måde at gøre en metode overskrivelig på?

question mark

Hvilke to nøgleord bruges ved metodeoverskrivning?

Select the correct answer

question mark

Hvad er den korrekte måde at gøre en metode overskrivelig på?

Select the correct answer

Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 5. Kapitel 4
some-alt