Zum Inhalt springen
C# Anfรคnger 30 min

Vererbung & Interfaces

Wiederverwendung und Polymorphie mit C#: Basisklassen, virtuelle Methoden, Interfaces und wann du was nutzen solltest.

Aktualisiert:
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
  • Hund ist eine Subklasse (oder abgeleitete Klasse) von Tier
  • Tier ist die Basisklasse
  • Hund hat alles von Tier plus 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!");
    }
}
  • virtual in der Basisklasse erlaubt Ueberschreiben
  • override in 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?

FrageAntwort
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/override fuer polymorphe Methoden
  • abstract fuer โ€œ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.

Zurรผck zum C# Kurs