Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lernen Polymorphismus | OOP-Prinzipien
C# Jenseits der Grundlagen

bookPolymorphismus

Der Begriff Polymorphismus bedeutet "in mehreren verschiedenen Formen vorkommend". Im Kontext der objektorientierten Programmierung bezeichnet Polymorphismus die Fähigkeit einer Klasse, eine gemeinsame Schnittstelle für ihre abgeleiteten Klassen bereitzustellen, während jede abgeleitete Klasse spezifische Verhaltensweisen für die geerbten Methoden implementieren kann.

Normalerweise wird beim Erstellen eines Objekts einer Klasse eine Variable erstellt, um die Referenz auf dieses Objekt zu speichern. Der Typ der Variablen entspricht dabei üblicherweise der Klasse dieses Objekts.

Beispiel:

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

Es ist jedoch auch möglich, eine Variable der Basisklasse zu erstellen und darin ein Objekt einer abgeleiteten Klasse zu speichern.

Beispiel:

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

Das Attribut breed des Dog-Objekts ist nicht zugänglich, weil das Dog-Objekt beim Speichern in einer Mammal-Variablen implizit in einen Mammal-Typ umgewandelt wird. Das bedeutet, dass nur auf die Attribute und Methoden zugegriffen werden kann, die in der Klasse Mammal vorhanden sind. Der Wert, der im Attribut breed gespeichert ist, geht dabei jedoch nicht verloren, sondern ist lediglich nicht zugänglich und kann als versteckt betrachtet werden.

Durch explizites Typecasting kann example einfach wieder in einen Dog umgewandelt werden, wodurch das Attribut breed wieder verfügbar ist:

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 Methoden gibt es jedoch eine zusätzliche Funktion namens Methodenüberschreibung (method overriding), die der Methodenüberladung (method overloading) ähnlich ist. In diesem Fall wird eine Methode der Basisklasse in der abgeleiteten Klasse neu definiert.

Beispielsweise könnte die Klasse Mammal eine Methode speak() besitzen, sodass sie Woof! ausgibt, wenn sie von einem Dog-Objekt aufgerufen wird, und Meow!, wenn sie von einem Cat-Objekt aufgerufen wird:

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

Die Warnungen, die bei dieser Kompilierung auftreten, entstehen durch sich überschneidende Methodennamen in Eltern- und Kindklassen. In diesem Fall gibt es Überschneidungen zwischen den speak-Methoden der Klassen Cat und Mammal sowie zwischen Dog und Mammal, weshalb zwei Warnungen ausgegeben werden.

Beachte jedoch, dass am Ende m1, m2 und m3 die Methode aus der Klasse Mammal ausführen, da sie in Mammal-Objekte umgewandelt wurden.

Wenn die Methode speak sich entsprechend dem ursprünglichen Objekttyp verhalten soll, kann sie einfach in eine virtuelle Methode umgewandelt werden. Eine virtuelle Methode ist eine Methode, die es erlaubt, sich in abgeleiteten Klassen zu überschreiben, sodass die konkrete Implementierung zur Laufzeit anhand des Typs des ursprünglichen Objekts bestimmt wird.

Um eine Methode virtuell zu machen, fügt man einfach das Schlüsselwort virtual vor dem Rückgabetyp hinzu:

index.cs

index.cs

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

Um eine überschriebene Implementierung dieser Methode zu erstellen, das Schlüsselwort override vor dem Rückgabetyp in der Implementierung der abgeleiteten Klasse dieser neuen Version verwenden:

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

Setzen wir nun die beiden Codeausschnitte zusammen und betrachten, wie sich dies auf die Ausgabe auswirkt:

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

In der Ausgabe ist zu erkennen, dass m2 und m3 die Implementierung der Methode von Cat bzw. Dog verwenden, da diese Objekte ursprünglich vom Typ Cat bzw. Dog waren. Dieser gesamte Prozess, bei dem Methoden überschrieben werden, sodass sie sich entsprechend ihres ursprünglichen Typs verhalten, wird als Polymorphismus bezeichnet.

Ein Anwendungsfall, in dem dies sehr nützlich sein kann, ist die Möglichkeit, Objekte verschiedener Datentypen in einem einzigen Array oder einer Liste zu speichern.

Beispiel:

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. Welche zwei Schlüsselwörter werden beim Überschreiben von Methoden verwendet?

2. Was ist die korrekte Vorgehensweise, um eine Methode überschreibbar zu machen?

question mark

Welche zwei Schlüsselwörter werden beim Überschreiben von Methoden verwendet?

Select the correct answer

question mark

Was ist die korrekte Vorgehensweise, um eine Methode überschreibbar zu machen?

Select the correct answer

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 5. Kapitel 4

Fragen Sie AI

expand

Fragen Sie AI

ChatGPT

Fragen Sie alles oder probieren Sie eine der vorgeschlagenen Fragen, um unser Gespräch zu beginnen

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

bookPolymorphismus

Swipe um das Menü anzuzeigen

Der Begriff Polymorphismus bedeutet "in mehreren verschiedenen Formen vorkommend". Im Kontext der objektorientierten Programmierung bezeichnet Polymorphismus die Fähigkeit einer Klasse, eine gemeinsame Schnittstelle für ihre abgeleiteten Klassen bereitzustellen, während jede abgeleitete Klasse spezifische Verhaltensweisen für die geerbten Methoden implementieren kann.

Normalerweise wird beim Erstellen eines Objekts einer Klasse eine Variable erstellt, um die Referenz auf dieses Objekt zu speichern. Der Typ der Variablen entspricht dabei üblicherweise der Klasse dieses Objekts.

Beispiel:

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

Es ist jedoch auch möglich, eine Variable der Basisklasse zu erstellen und darin ein Objekt einer abgeleiteten Klasse zu speichern.

Beispiel:

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

Das Attribut breed des Dog-Objekts ist nicht zugänglich, weil das Dog-Objekt beim Speichern in einer Mammal-Variablen implizit in einen Mammal-Typ umgewandelt wird. Das bedeutet, dass nur auf die Attribute und Methoden zugegriffen werden kann, die in der Klasse Mammal vorhanden sind. Der Wert, der im Attribut breed gespeichert ist, geht dabei jedoch nicht verloren, sondern ist lediglich nicht zugänglich und kann als versteckt betrachtet werden.

Durch explizites Typecasting kann example einfach wieder in einen Dog umgewandelt werden, wodurch das Attribut breed wieder verfügbar ist:

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 Methoden gibt es jedoch eine zusätzliche Funktion namens Methodenüberschreibung (method overriding), die der Methodenüberladung (method overloading) ähnlich ist. In diesem Fall wird eine Methode der Basisklasse in der abgeleiteten Klasse neu definiert.

Beispielsweise könnte die Klasse Mammal eine Methode speak() besitzen, sodass sie Woof! ausgibt, wenn sie von einem Dog-Objekt aufgerufen wird, und Meow!, wenn sie von einem Cat-Objekt aufgerufen wird:

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

Die Warnungen, die bei dieser Kompilierung auftreten, entstehen durch sich überschneidende Methodennamen in Eltern- und Kindklassen. In diesem Fall gibt es Überschneidungen zwischen den speak-Methoden der Klassen Cat und Mammal sowie zwischen Dog und Mammal, weshalb zwei Warnungen ausgegeben werden.

Beachte jedoch, dass am Ende m1, m2 und m3 die Methode aus der Klasse Mammal ausführen, da sie in Mammal-Objekte umgewandelt wurden.

Wenn die Methode speak sich entsprechend dem ursprünglichen Objekttyp verhalten soll, kann sie einfach in eine virtuelle Methode umgewandelt werden. Eine virtuelle Methode ist eine Methode, die es erlaubt, sich in abgeleiteten Klassen zu überschreiben, sodass die konkrete Implementierung zur Laufzeit anhand des Typs des ursprünglichen Objekts bestimmt wird.

Um eine Methode virtuell zu machen, fügt man einfach das Schlüsselwort virtual vor dem Rückgabetyp hinzu:

index.cs

index.cs

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

Um eine überschriebene Implementierung dieser Methode zu erstellen, das Schlüsselwort override vor dem Rückgabetyp in der Implementierung der abgeleiteten Klasse dieser neuen Version verwenden:

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

Setzen wir nun die beiden Codeausschnitte zusammen und betrachten, wie sich dies auf die Ausgabe auswirkt:

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

In der Ausgabe ist zu erkennen, dass m2 und m3 die Implementierung der Methode von Cat bzw. Dog verwenden, da diese Objekte ursprünglich vom Typ Cat bzw. Dog waren. Dieser gesamte Prozess, bei dem Methoden überschrieben werden, sodass sie sich entsprechend ihres ursprünglichen Typs verhalten, wird als Polymorphismus bezeichnet.

Ein Anwendungsfall, in dem dies sehr nützlich sein kann, ist die Möglichkeit, Objekte verschiedener Datentypen in einem einzigen Array oder einer Liste zu speichern.

Beispiel:

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. Welche zwei Schlüsselwörter werden beim Überschreiben von Methoden verwendet?

2. Was ist die korrekte Vorgehensweise, um eine Methode überschreibbar zu machen?

question mark

Welche zwei Schlüsselwörter werden beim Überschreiben von Methoden verwendet?

Select the correct answer

question mark

Was ist die korrekte Vorgehensweise, um eine Methode überschreibbar zu machen?

Select the correct answer

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 5. Kapitel 4
some-alt