Skip to content

Vererbung

Einleitung

Vererbung ist ein zentrales Konzept der objektorientierten Programmierung. Es wird verwendet, wenn man Objekte verwalten will, die die gleiche Basisfunktionalität bieten und gleichzeitig verschiedene spezielle Ausprägungen haben.

// Basisklasse
class Fahrzeug
{
public string Marke { get; set; }
public int Baujahr { get; set; }
public void Starten()
{
Console.WriteLine($"Das Fahrzeug der Marke {Marke} (Baujahr {Baujahr}) startet.");
}
}
// Abgeleitete Klasse: Auto
class Auto : Fahrzeug
{
public int Sitzplätze { get; set; }
public void Hupen()
{
Console.WriteLine("Das Auto hupt: Hup Hup!");
}
}
// Abgeleitete Klasse: Motorrad
class Motorrad : Fahrzeug
{
public bool HatBeifahrersitz { get; set; }
public void Wheelie()
{
Console.WriteLine("Das Motorrad macht einen Wheelie!");
}
}
class Program
{
static void Main(string[] args)
{
// Ein Auto erstellen und seine Eigenschaften nutzen
Auto meinAuto = new Auto
{
Marke = "VW", // Eigenschaft von Fahrzeug geerbt
Baujahr = 2020, // Eigenschaft von Fahrzeug geerbt
Sitzplätze = 5 // Spezielle Eigenschaft von Auto
};
meinAuto.Starten(); // Methode von Fahrzeug geerbt
meinAuto.Hupen(); // Spezielle Methode von Auto
Console.WriteLine($"Das Auto hat {meinAuto.Sitzplätze} Sitzplätze.");
Console.WriteLine();
// Ein Motorrad erstellen und seine Eigenschaften nutzen
Motorrad meinMotorrad = new Motorrad
{
Marke = "Yamaha", // Eigenschaft von Fahrzeug geerbt
Baujahr = 2018, // Eigenschaft von Fahrzeug geerbt
HatBeifahrersitz = true // Spezielle Eigenschaft von Motorrad
};
meinMotorrad.Starten(); // Methode von Fahrzeug geerbt
meinMotorrad.Wheelie(); // Spezielle Methode von Motorrad
Console.WriteLine($"Das Motorrad hat einen Beifahrersitz: {meinMotorrad.HatBeifahrersitz}");
}
}

Durch Vererbung erreicht man, dass Properties und Methoden, die für alle Klassen der Vererbungshierarchie gleich funktionieren, nur einmal in der Basisklasse definiert werden müssen. Alle abgeleiteten Klassen haben Zugriff auf die Properties und Methoden der Basisklasse, solange diese nicht private sind.

Begriffe: Ableitung und Vererbung

Folgende Ausdrucksweisen sind gleichbedeutend:

  • Die Klasse Fahrzeug vererbt an Motorrad und Auto
  • Die Klassen Motorrad und Auto leiten von Fahrzeug ab.
  • Die Klassen Motorrad und Auto erben von Fahrzeug.
  • Englisch: Inheritance = Vererbung, to derive = ableiten

Eine Klasse die an andere Klassen vererbt nennt man auch Basisklasse. Eine Klasse die von einer anderen Klasse ableitet nennt man auch abgeleitete Klasse.

Darstellung in der UML

In der UML (Unified Modelling Language) wird Vererbung dargestellt durch zwei Klassen, die durch einen Pfeil verbunden sind, wobei die Pfeilspitze ein nicht ausgefülltes Dreieck ist. Abgeleitete Klassen beinhalten nur die Properties und Methoden die neu hinzukommen. Vererbte Properties und Methoden werden nicht noch einmal angeführt.

Abstrakte Basisklassen

Manchmal möchte man Basisklassen erstellen, um dort die Dinge zu definieren, die für abgeleitete Klassen gleich sein sollen, jedoch ohne eine Möglichkeit zu bieten die Basisklasse selbst zu instanziieren. Dafür kann man die Basisklasse als abstract markieren:

// Abstrakte Basisklasse
abstract class Tier
{
public string Name { get; set; }
// Normale Methode (kann von den abgeleiteten Klassen verwendet werden)
public void Bewegen()
{
Console.WriteLine($"{Name} bewegt sich.");
}
}
// Abgeleitete Klasse: Hund
class Hund : Tier
{
}
class Program
{
static void Main(string[] args)
{
// Ein Hund erstellen
Tier meinHund = new Hund { Name = "Bello" };
meinHund.Bewegen();
Tier meinTier = new Tier(); // Fehler: abstrakte Klasse Tier kann nicht instanziiert werden.
}
}

Abstrakte Basisklassen bieten auch die Möglichkeit Methoden als abstrakt zu definieren. Damit können bereits in der Basisklasse Methoden definiert werden, ohne jedoch eine Implementierung anzugeben. Damit sagt man: Jede Klasse die von dieser Klasse ableitet, muss diese Methode implementieren, oder selbst auch wieder eine abstrakte Klasse sein. Abgeleitete Klassen verwenden beim Implementieren der Methode das Schlüsselwort override.

// Abstrakte Basisklasse
abstract class Tier
{
public string Name { get; set; }
// Abstrakte Methode (muss von den abgeleiteten Klassen implementiert werden)
public abstract void MachGeräusch();
// Normale Methode (kann von den abgeleiteten Klassen verwendet werden)
public void Bewegen()
{
Console.WriteLine($"{Name} bewegt sich.");
}
}
// Abgeleitete Klasse: Hund
class Hund : Tier
{
public override void MachGeräusch()
{
Console.WriteLine($"{Name} bellt: Wuff Wuff!");
}
}
class Program
{
static void Main(string[] args)
{
// Ein Hund erstellen
Tier meinHund = new Hund { Name = "Bello" };
meinHund.Bewegen();
meinHund.MachGeräusch();
}
}

Vererbungshierarchie

Vererbung ist nicht auf eine Ebene beschränkt. Abgeleitete Klassen können wiederum Basisklassen für andere Klassen sein. Es gibt keine Einschränkung wie oft abgeleitet werden kann.

class A {} // Basisklasse
class B : A {} // abgeleitete Klasse B, leitet von A ab, ist selbst wieder Basisklasse
class C : B {} // abgeleitete Klasse C, leitet von B ab

Mehrfachvererbung

Mehrfachvererbung bedeutet, dass eine Klasse von mehreren Basisklassen ableiten kann. In C# ist Mehrfachvererbung nicht erlaubt. Eine Klasse kann immer nur von genau einer Basisklasse ableiten.

class A {}
class B {}
class C : A, B {} // error: cannot derive from two classes

Polymorphismus

In den Code-Bespielen oben ist dir vielleicht folgende Zeile aufgefallen:

Tier meinHund = new Hund { Name = "Bello" };

Wir haben eine Variable vom Typ Tier definiert, dieser Variable wurde jedoch kein Tier zugewiesen, sondern eine Objektinstanz vom Typ Hund. Dieses Beispiel zeigt Polymorphismus. Der Begriff steht für “Vielgestaltigkeit” und meint, dass eine Variable mehrere unterschiedliche Ausprägungen annehmen kann. C# ist eine statisch typisierte Sprache. Das bedeutet, dass zur Compile-Zeit bereits festgelegt ist, welchen Datentyp eine Variable aufnehmen kann. In diesem Beispiel ist der statische Datentyp Tier. Polymorphismus ermöglicht es jedoch, dass die Variable nicht nur genau den angegeben Datentyp aufnehmen kann, sondern auch jeglichen davon abgeleiteten Datentyp. In diesem Beispiel ist der dynamische Datentyp Hund.

Achtung, Polymorphismus funktioniert nur in eine Richtung. Die Variable eines statischen Datentyps kann den Datentyp selbst, oder eine abgeleitete Klasse aufnehmen, nicht jedoch eine Basisklasse.

class A {}
class B : A {}
A a1 = new A(); // OK
A a2 = new B(); // OK (Polymorphism)
B b1 = new B(); // OK
B b2 = new A(); // Error: You can only assign B or derived types.

Dynamische Bindung

Wird eine abstrakte Methode einer Basisklasse aufgerufen, oder eine Methode die mit dem Schlüsselwort virtual versehen wurde, so wird dynamische Bindung ermöglicht. Das bedeutet, dass beim Aufruf der Methode, nicht zwingend die Methode des statischen Datentyps aufgerufen wird, sondern diejenige des dynamischen Datentyps. Dank Polymorphismus müssen die beiden ja nicht übereinstimmen.

// Abstrakte Basisklasse
abstract class Tier
{
public string Name { get; set; }
// Abstrakte Methode (muss von den abgeleiteten Klassen implementiert werden, ermöglicht dynamische Bindung)
public abstract void MachGeräusch();
// Normale Methode (kann von den abgeleiteten Klassen verwendet werden)
public void Bewegen()
{
Console.WriteLine($"{Name} bewegt sich.");
}
// Virtuelle Methode (kann von abgeleiteten Klassen überschrieben werden, ermöglicht dynamische Bindung)
public virtual void Fressen()
{
Console.WriteLine($"{Name} frisst.");
}
}
// Abgeleitete Klasse: Hund
class Hund : Tier
{
public override void MachGeräusch()
{
Console.WriteLine($"{Name} bellt: Wuff Wuff!");
}
public override void Fressen()
{
Console.WriteLine($"{Name} frisst gierig.");
}
}
class Program
{
static void Main(string[] args)
{
// Ein Hund erstellen
Tier meinHund = new Hund { Name = "Bello" };
meinHund.Bewegen(); // normaler Methodenaufruf - Methode von statischen Typ Tier wird aufgerufen
meinHund.MachGeräusch(); // Methodenaufruf mit dynamischer Bindung - Methode von Hund wird aufgerufen
meinHund.Fressen(); // Methodenaufruf mit dynamischer Bindung - Methode von Hund wird aufgerufen
}
}