Vererbung & Interfaces
Wiederverwendung und Polymorphie mit C#: Basisklassen, virtuelle Methoden, Interfaces und wann du was nutzen solltest.
Inhaltsverzeichnis
Vererbung & Interfaces
Mit Vererbung und Interfaces strukturierst du Code so, dass verwandte Klassen sich Verhalten teilen und austauschbar sind.
Vererbung - Basics
Eine Klasse erbt von einer anderen mit ::
public class Tier
{
public string Name { get; init; }
public void Atmen()
{
Console.WriteLine($"{Name} atmet.");
}
}
public class Hund : Tier
{
public void Bellen()
{
Console.WriteLine($"{Name} bellt: Wuff!");
}
}
var bello = new Hund { Name = "Bello" };
bello.Atmen(); // geerbt
bello.Bellen(); // eigene
Hundist eine Subklasse (oder abgeleitete Klasse) vonTierTierist die BasisklasseHundhat alles vonTierplus eigene Erweiterungen
base - Basisklasse ansprechen
public class Hund : Tier
{
public Hund(string name)
{
Name = name; // Feld ist in Tier definiert
}
public void Vorstellen()
{
base.Atmen(); // Methode der Basisklasse aufrufen
Console.WriteLine("Ich bin ein Hund.");
}
}
Basis-Konstruktor aufrufen
Wenn die Basisklasse einen Konstruktor mit Parametern hat:
public class Tier
{
public string Name { get; }
public Tier(string name) { Name = name; }
}
public class Hund : Tier
{
public string Rasse { get; }
public Hund(string name, string rasse) : base(name)
{
Rasse = rasse;
}
}
: base(name) ruft den Konstruktor der Basisklasse auf.
Virtuelle Methoden und Override
Methoden der Basisklasse kannst du in Subklassen ueberschreiben - wenn die Basisklasse es erlaubt:
public class Tier
{
public virtual void GeraeuschMachen()
{
Console.WriteLine("Irgendein Tier-Geraeusch");
}
}
public class Hund : Tier
{
public override void GeraeuschMachen()
{
Console.WriteLine("Wuff!");
}
}
public class Katze : Tier
{
public override void GeraeuschMachen()
{
Console.WriteLine("Miau!");
}
}
virtualin der Basisklasse erlaubt Ueberschreibenoverridein der Subklasse ueberschreibt
Polymorphie in Aktion
Tier[] tiere = {
new Hund(),
new Katze(),
new Tier()
};
foreach (var t in tiere)
{
t.GeraeuschMachen(); // ruft immer die richtige Version auf
}
// Wuff!
// Miau!
// Irgendein Tier-Geraeusch
Der Laufzeittyp entscheidet - das ist Polymorphie.
Abstrakte Klassen
Eine abstract-Klasse kann nicht direkt instanziiert werden. Sie definiert Verpflichtungen fuer Subklassen:
public abstract class Form
{
public abstract double Flaeche(); // muss in Subklassen implementiert werden
public void Info()
{
Console.WriteLine($"Flaeche: {Flaeche()}");
}
}
public class Kreis : Form
{
public double Radius { get; init; }
public override double Flaeche() => Math.PI * Radius * Radius;
}
public class Rechteck : Form
{
public double Breite { get; init; }
public double Hoehe { get; init; }
public override double Flaeche() => Breite * Hoehe;
}
new Form() geht nicht - du musst ein konkretes Kind instanziieren.
sealed - Vererbung verbieten
Wenn du nicht willst, dass eine Klasse weiter vererbt wird:
public sealed class FinaleKlasse { }
Oder eine einzelne Methode:
public sealed override void GeraeuschMachen() { }
Interfaces
Ein Interface beschreibt nur was ein Typ koennen muss - nicht wie. Klassen implementieren Interfaces.
public interface IZahlbar
{
decimal BerechneBetrag();
string Beschreibung { get; }
}
Konvention: Interface-Namen starten mit I.
Implementieren
public class Rechnung : IZahlbar
{
public string Beschreibung { get; init; } = "Rechnung";
public decimal Netto { get; init; }
public decimal SteuerSatz { get; init; } = 0.19m;
public decimal BerechneBetrag() => Netto * (1 + SteuerSatz);
}
public class Abo : IZahlbar
{
public string Beschreibung { get; init; } = "Abo";
public decimal MonatsBetrag { get; init; }
public int Monate { get; init; }
public decimal BerechneBetrag() => MonatsBetrag * Monate;
}
Polymorphie mit Interfaces
Was beide gemeinsam haben, kannst du ueber das Interface nutzen:
IZahlbar[] posten = {
new Rechnung { Netto = 100m },
new Abo { MonatsBetrag = 9.99m, Monate = 12 }
};
decimal summe = 0;
foreach (var p in posten)
{
Console.WriteLine($"{p.Beschreibung}: {p.BerechneBetrag():C}");
summe += p.BerechneBetrag();
}
Console.WriteLine($"Gesamt: {summe:C}");
Mehrere Interfaces
Eine Klasse kann nur eine Basisklasse haben, aber mehrere Interfaces:
public class Produkt : IZahlbar, IVergleichbar, IDruckbar
{
// Implementierungen...
}
Default-Implementierungen (C# 8+)
Interfaces koennen heute auch Standard-Implementierungen mitbringen:
public interface IBegrueser
{
string Name { get; }
void Begruessen() => Console.WriteLine($"Hallo, {Name}!");
}
Wenn die Klasse Begruessen nicht ueberschreibt, wird die Default-Variante genutzt.
Interface oder Basisklasse?
| Frage | Antwort |
|---|---|
| Teile ich Daten und Verhalten? | Basisklasse |
| Gibt es eine is-a-Beziehung? | Basisklasse |
| Will ich nur einen Vertrag definieren? | Interface |
| Brauche ich Mehrfach-โVererbungโ? | Interface |
| Soll ein Typ eine Faehigkeit erhalten? | Interface |
Faustregel: Interface fuer Faehigkeiten (IDisposable, IComparable, IEnumerable), Basisklasse fuer geteilte Datenmodelle.
Pattern: Komposition statt Vererbung
Tief verschachtelte Vererbungsbaeume werden schnell unuebersichtlich. Oft ist Komposition (ein Objekt besitzt ein anderes) flexibler:
public class Auto
{
private readonly Motor _motor;
private readonly Getriebe _getriebe;
public Auto(Motor motor, Getriebe getriebe)
{
_motor = motor;
_getriebe = getriebe;
}
}
Statt Auto : Motor machst du Auto mit einem Motor.
Praktisches Beispiel
public abstract class Mitarbeiter
{
public string Name { get; init; }
public abstract decimal Gehalt();
}
public class Festangestellter : Mitarbeiter
{
public decimal Monatsgehalt { get; init; }
public override decimal Gehalt() => Monatsgehalt;
}
public class Stundenlohn : Mitarbeiter
{
public decimal Stundensatz { get; init; }
public int Stunden { get; init; }
public override decimal Gehalt() => Stundensatz * Stunden;
}
Mitarbeiter[] team = {
new Festangestellter { Name = "Anna", Monatsgehalt = 4500m },
new Stundenlohn { Name = "Max", Stundensatz = 25m, Stunden = 120 }
};
foreach (var m in team)
Console.WriteLine($"{m.Name}: {m.Gehalt():C}");
Zusammenfassung
- Vererbung mit
:- Subklasse erbt Verhalten der Basisklasse virtual/overridefuer polymorphe Methodenabstractfuer โdarf nicht instanziiert werdenโ + Pflicht-Methoden- Interfaces fuer Vertraege - Mehrfach-Implementierung moeglich
- Default-Methoden im Interface sind erlaubt (C# 8+)
- Komposition schlaegt haeufig tiefe Vererbung
Mit diesen Werkzeugen kannst du jetzt realistische C#-Projekte bauen. Im weiteren Kurs vertiefen wir Collections, LINQ, Generics, async/await und Exception Handling.