Vererbung ermöglicht es, eine Klasse zu erstellen und deren Eigenschaften und Methoden an abgeleitete Klassen weiterzugeben. Dadurch kann der Code wiederverwendet sowie die Struktur des Softwarecode werden.
Grundlagen der Vererbung in C#
- Basisklasse (Parent): Die ursprüngliche Klasse, von der andere Klassen erben.
- Abgeleitete Klasse (Child): Die Klasse, welche die Eigenschaften und Methoden der Basisklasse übernimmt und erweitern kann.
Fallbeispiel
Ein ganz einfaches Beispiel, welches oft verwendet wird ist immer das Fahrzeuge. Dieses Beispiel verwende ich hier da zum einen nahezu jedem Fahrzeuge bekannt sind und zum anderen um spätere Beispielcodes aufbauend auf diesem Code zu verwenden.
Überlegung
Wir benötigen ein Auto, ein Motorrad und ein LKW. Alle drei Arten von Fahrzeuge haben gemeinsame Eigenschaften und Methoden, welche alle drei Fahrzeuge verwenden. Allerdings haben auch alle 3 Fahrzeugtypen unterschiedliche Methoden. Beispiel viele Motorräder können nicht rückwärts Fahren oder ein LKW kann die Fahrerkabine zur Reparatur herunterfahren. Ich selber bin kein Fahrzeugexperte, aber ich kann den Unterschied zwischen Adaptiv- und Leichtgewichtrollstuhl erklären :).
Beispiel einer (kleinen) Basisklasse:
public abstract class Fahrzeug{
/// <summary>
/// Farbe des Fahrzeug
/// </summary>
/// <remarks>
/// Standardfarbe = Schwarz
/// </remarks>
public System.Drawing.Color FahrzeugFarbe { get; set; } = System.Drawing.Color.Black;
/// <summary>
/// Fahrzeug fährt vorwärts
/// </summary>
public void FahrenVorwaerts() {
Console.WriteLine("Das Fahrzeug fährt.");
}
/// <summary>
/// Fahrzeug Hupt
/// </summary>
public void Hupen() {
Console.WriteLine("Das Fahrzeug hupt.");
}
/// <summary>
/// Fahrzeug fährt rückwärts
/// </summary>
/// <remarks>
/// Besonderheit: nicht jedes Fahrzeug kann rückwärts fahren!
/// </remarks>
public virtual void FahrenRueckwaerts(){
Console.WriteLine("Das Fahrzeug fährt.");
}
}
Die oben gezeigte Basisklasse „Fahrzeug“ besitzt das Attribut Farbe, welches als Standard Schwarz ist, dazu die Methoden FahrenVorwaerts, FahrenRückwaerts sowie Hupen.
Dabei ist zu beachten das nicht jedes Fahrzeug rückwärts Fahren kann, daher habe ich in diesem Beispiel eine Methodenüberschreibung (override) erlaubt, was mit dem Schlüsselwort „virtual“ erlaubt wird.
Um ein Überschreiben von Methoden, Funktionen oder Eigenschaften (Attribute) zu erlauben, muss in der Basisklasse Basis- methode/-funktion/-Eigenschaft „virtual“ sein. Diese kann dann in der Kindklasse mit „override“ überschrieben werden.
Kindklassen
/// <summary>
/// Auto Klasse
/// </summary>
/// <remarks>Erbt von Fahrzeug</remarks>
public class Auto : Fahrzeug {
/// <summary>
/// Konstrukt für Auto
/// </summary>
/// <param name="farbe">Farbe</param>
public Auto(System.Drawing.Color farbe)
{
base.FahrzeugFarbe = farbe;
base.ReifenAnzahl = 4;
base.PS = 180;
}
}
/// <summary>
/// Motorrad Klasse
/// </summary>
/// <remarks>Erbt von Fahrzeug</remarks>
public class Motorrad : Fahrzeug
{
/// <summary>
/// Konstrukt für Motorrad
/// </summary>
/// <param name="farbe">Farbe</param>
public Motorrad (System.Drawing.Color farbe)
{
base.FahrzeugFarbe = farbe;
base.ReifenAnzahl = 2;
base.PS = 35;
}
public override void FahrenRueckwaerts()
{
Console.WriteLine("Kindklasse: Das Motorrad hat keinen Rückwärtsgang!");
}
}
/// <summary>
/// LKW Klasse
/// </summary>
/// <remarks>Erbt von Fahrzeug</remarks>
public class LKW : Fahrzeug
{
/// <summary>
/// Konstrukt für LKW
/// </summary>
/// <param name="farbe">Farbe</param>
public LKW(System.Drawing.Color farbe)
{
base.FahrzeugFarbe = farbe;
base.ReifenAnzahl = 6;
base.PS = 476;
}
/// <summary>
/// Fahrerhaus kippen
/// </summary>
/// <remarks>
/// diese Funktion besitzen nur LKWs</remarks>
public void FahrerhausKippen() {
Console.WriteLine("Kindklasse: Das Fahrerhaus wird gekippt!");
}
}
Da der Code der abgeleiteten Klassen (im Code Kindklasse oder auch Child genannt) nicht viel passiert, habe ich 1 Listening des Beispielcodes aller abgeleiteter Klassen verwendet.
Die abgeleiteten Klassen ändern sich nur gering.
Die Klasse „Auto“ besitzt sämtliche Attribute und Methoden der Basisklasse.
Die Klasse „Motorrad“ überschreibt die Methode „FahrenRueckwaerts“ da das erdachte Motorrad kein Rückwärtsgang hat. In der Konsole erscheint die Meldung „Kindklasse: Das Motorrad hat keinen Rückwärtsgang“.
Die Klasse „LKW“ hat eine weitere Methode, welche das Kippen des Fahrerhaus ermöglicht.
Wichtige Aspekte bei der Vererbung
- Basisklassenaufruf
- Das base-Schlüsselwort auf Konstruktoren, Methoden, Funktionen oder Attribute der Basisklasse.
- Methodenüberschreibungen
- Ermöglicht es, das geerbte Methoden, Funktionen oder Attribute innerhalb der Abgeleiteten(Child) Klasse zu verändern.
- Um eine Methode, Funktion oder ein Attribute zu überschreiben muss diese Methode, Funktion oder das Attribute virtual sein.
Virtuelle Methode, Funktion oder ein Attribute können mit override überschrieben werden (Beispiel in der abgeleiteten Klasse Motorrad public override void FahrenRueckwaerts())
- Abstrakte Klassen
- In diesem Einführungsbeispiel sind keine Abstrakten Klassen vorhanden. Wird eine Klasse Abstrakt deklariert (Beispiel public abstract class Fahrzeug) kann diese Klasse nicht direkt Instanziiert werden, sondern dient nur als Vorlage für abgeleitete Klassen.
Gesamter Quellcode als Download (Visual Studio Projekt).
Dies ist ein kleines, einfaches und nicht so überladenes Beispiel welches ein ersten Einblick in die Vererbung welches bei der Objektorientierten Programmierung (OOP) ein Grundlegendes Konzept ist.
Viele Aufgaben des Programmierers wiederholen sich, ob es einfache Rechenaufgaben sind (wie z.B. die Mehrwertsteuer berechnen) oder wie hier in diesem Beispiel „Fahren“ ist. Es kann sich so an das DRY Prinzip gehalten werden (DRY = Don’t Repeat Yourself). In diesem Beispiel hier währen es die Methoden Hupen und FahreVorwaerts welche nicht doppelt geschrieben werden müssen. Das erleichtert die Wartung. Besitzt zum Beispiel die Methode Hupen() ein Fehler, muss diese nur 1x korrigiert werden damit alle Fahrzeuge den Fehler in der Methode Hupen korrigiert bekommen. Wenn wir die Methode Hupen in jeder Klasse (also Auto, Motorrad und LKW) hätten, müssten wir bei einem Fehlerfall diese Funktion 3x korrigieren.
Bei vielen größeren und älteren Programmen habe ich selber erleben müssen das sich einige Programmierer nicht an das DRY Prinzip gehalten haben, unter anderem auch weil ein Programm nicht mittels OOP erstellt worden ist. Gerade in Fremden Codes ist die
1. Wartbarkeit in diesem Moment schwer zu bewerkstelligen
2. Der Code ist unübersichtlich
3. Redundante Code-Duplikate erhöhen das Risiko für inkonsistente Änderungen.