Polymorphie (Überladen/Überschreiben)

Werbung
Polymorphie
Überladen / Überschreiben
• Definition
• Methodennamen überladen
• Methoden überschreiben
• Konstruktoren überladen
• Beispiele
Dr. Beatrice Amrhein
Definition
2
Definition: Überladen (von Namen)
Überladen bedeutet, dass ein Methodenname in einer Klasse
für mehrere Methoden verwendet wird.
Damit das Überladen möglich ist, muss wenigstens eine der
beiden Voraussetzungen erfüllt sein:
o Der Datentyp mindestens eines Übergabeparameters ist anders als in
den anderen gleichnamigen Methoden.
o Die Anzahl der Übergabeparameter ist unterschiedlich.
Beispiel, überladen des Namens add
int add( int a, int b ){ return a+b; }
float add( int a, int b, float c ){ return a+b+c; }
3
Definition: Überschreiben (von Methoden)
Eine Methode kann in einer davon abgeleiteten Klasse
überschrieben werden.
Beim Überschreiben einer Methode müssen die beiden
Methodensignaturen (Methodenname, Parameterliste,
Rückgabewert) exakt(!) übereinstimmen.
class BasisKlasse
{
public virtual int MachEtwas(int a)
{ return a + a; }
}
class AbgeleiteteKlasse:BasisKlasse
{
public override int MachEtwas(int a)
{ return a * a; }
}
4
Methodennamen
überladen
5
Regeln für das Überladen
Methoden, welche den gleichen Namen, aber eine
unterschiedliche Parameterliste haben, heissen überladene
Methoden.
Die zwei Methoden dürfen sich aber nicht nur durch den
Rückgabewert oder den Zugriffs-Modifizierer (public, private,
…) unterscheiden.
6
Beispiel Klasse Addierer
Die Klasse Addierer habe für verschiedene Typen verschiedene addMethoden
class Addierer
{
public int add(int a, int b)
{ return a + b; }
public int add(int a, int b, int c)
{ return a + b + c; }
// drei Parameter, ok
public float add(float a, float b)
{ return a + b; }
// andere Typen, ok
//Unterscheidung nur durch Rückgabewert und Modifizierer
private void add(int a, int b)
// Fehler!!
{ Console.WriteLine(a + b); }
}
7
Stil-Regeln für das Überladen
Überladene Methoden müssen Varianten der gleichen
Funktionalität bereitstellen (alle Methoden machen etwas
ähnliches)
Es ist guter Stil, wenn die Namen und die Reihenfolge der
gemeinsamen Parameter möglichst gleich bleiben.
Es ist erlaubt, aber schlechter Stil, wenn sich die Methoden
nur durch die Reihenfolge der Parameter-Typen
unterscheiden.
// korrekt, aber schlechter Stil
public float add(int a, float b) { return a + b; }
public float add(float a, int b) { return a + b; }
8
Beispiel Klasse Information
Die Methode Ausgabe der Klasse Information soll verschiedenartige Daten
ausgeben.
class Information
{
public String Ausgabe(String s, int a)
{ return String.Format("{0}: {1}", s, a); }
public String Ausgabe(String s, int a, int b)
{ return String.Format("{0}: {1}, {2}", s, a, b); }
//Syntaktisch in Ordnung, aber schlechter Stil
public void Ausgabe(int a, String s)
{ Console.WriteLine("{0}: {1}", s, a); }
//Unterscheidung nur durch Parametername
public String Ausgabe(String s, int e)
{ return String.Format("{0}: {1}", s, e); }
gleiche Funktionalität
mit mehr Parameter, ok
andere Funktionalität
und andere Reihenfolge
// Fehler!!!
}
9
Methoden überschreiben
10
Virtual und Override
Die Methode der Basisklasse welche durch die Methode der abgeleiteten
Klasse überschrieben werden soll, muss dies durch das Schlüsselwort
virtual zulassen
public virtual int MachEtwas(int a)
{
return a + a;
}
Die Methode der abgeleiteten Klasse, welche die Methode der Basisklasse
überschriebt, muss die gleiche Signatur haben und das Überrschreiben
durch das Schlüsselwort override anzeigen
public override int MachEtwas(int a)
{
return a * a;
}
11
Beispiel Methode MachEtwas
BasisKlasse mit Methode MachEtwas()
class BasisKlasse
{
public virtual int MachEtwas(int a)
{
return a + a;
}
}
AbgeleiteteKlasse mit überschriebener Methode MachEtwas()
class AbgeleiteteKlasse:BasisKlasse
{
public override int MachEtwas(int a)
{
return a * a;
}
}
12
Benutzen von überschriebenen Methoden
static void Main(string[] args)
{
BasisKlasse b = new BasisKlasse();
Console.WriteLine("BasisKlasse: {0}", b.MachEtwas(3));
AbgeleiteteKlasse a = new AbgeleiteteKlasse();
Console.WriteLine("AbgeleiteteKlasse: {0}", a.MachEtwas(3));
}
13
Nicht überschriebene Methoden
Virtuelle Methoden müssen nicht zwingend überschrieben werden.
class BasisKlasse
{
public virtual int MachEtwas(int a)
{ return a + a; }
public virtual int MachEtwasAnderes(int a)
{ return 3 * a; }
}
class AbgeleiteteKlasse:BasisKlasse
{
public override int MachEtwas(int a)
{ return a * a; }
}
Die abgeleitete Klasse kann, muss
aber die virtuellen Methoden der
Basis-Klasse nicht zwingend
überschreiben.
Fehlende, nicht überschriebene
Methoden werden vererbt.
14
Benutzen von nicht überschriebenen Methoden
static void Main(string[] args)
{
BasisKlasse b = new BasisKlasse();
Console.WriteLine("MachEtwas von BasisKlasse: {0}", b.MachEtwas(4));
AbgeleiteteKlasse a = new AbgeleiteteKlasse();
Console.WriteLine("MachEtwas von AbgeleiteteKlasse: {0}",
a.MachEtwas(4));
Console.WriteLine("MachEtwasAnderes von AbgeleiteteKlasse: {0}",
a.MachEtwasAnderes(4));
}
MachEtwasAnderes wurde in der
abgeleiteten Klasse nicht überschrieben,
also erbt AbgeleiteteKlasse die
Methode von der BasisKlasse.
15
Überladen von
Konstruktoren
16
Standard-Konstruktor
Konstruktoren werden benötigt um mit dem Aufruf new ein neues Objekt
dieser Klasse zu erzeugen. Konstruktoren haben denselben Namen wie die
Klasse und initialisieren normalerweise die Felder des neuen Objekts.
Wenn eine Klasse keinen Konstruktor enthält, wird automatisch ein leerer
Standard-Konstruktor erzeugt.
Beim Aufruf von new Beispiel() wird ein Objekt vom Typ Beispiel mit
dem Feld id erzeugt und mit 0 initialisiert. Der leere Konstruktor ist
optional und könnte weggelassen werden.
class Beispiel
{
int id = 0;
public Beispiel() { }
}
17
Überladener Konstruktor
Auch Konstruktoren können überladen werden. Auch für Sie gilt die
gleiche Regel, dass sich die Typen der Parameter der verschiedenen
Konstruktoren unterscheiden müssen.
Die verschiedenen Konstruktoren können sich mit dem Schlüsselwort
this() gegenseitig aufrufen.
class Beispiel
{
private int id;
private String name;
public Beispiel(int i) { id = i; }
public Beispiel(int i, String n) : this(i)
{
name = n;
}
}
18
Beispiel Klasse Person mit drei Konstruktoren
public class Person
{
static private int id;
private String firstName="-";
private String lastName="-";
private int year = 0;
ohne Parameter
public Person( ) {
id++; }
public Person(String f, String l) : this()
{ firstName = f; lastName = l; }
public Person(String f, String l, int y) : this(f, l)
{ year = y; }
zwei Parameter
drei Parameter
public String getInfo()
{
String result = String.Format("{0}: {1} {2}", id, firstName, lastName);
if (year != 0) result += ", " + year;
return result;
}
}
19
Beispiel: Mietobjekte
20
Basisklasse für Mietobjekte (Fahrzeuge)
class MietObjekt
{
protected String type;
protected double tagesMietPreis;
protected double kmPreis = 0;
protected MietObjekt(String t, double p)
{
this.type = t; this.tagesMietPreis = p;
}
21
Basisklasse für Mietobjekte (Fahrzeuge)
public virtual double GesamtPreis(int tage, int km)
{
return tagesMietPreis * tage;
}
public virtual String Ausgabe()
{
String resultat = " Typ: " + type;
resultat = resultat + "\n Preis pro Tag: " + tagesMietPreis;
return resultat;
}
}
22
Die Klasse PKW
class PKW : MietObjekt
{
private int plaetze;
// Zwei Konstruktoren
public PKW(String type, double preis, int pl)
: base(type, preis)
{
this.plaetze = pl;
}
public PKW(String type, double preis) : this(type, preis, 4)
{
}
23
Die Klasse PKW
// überschreiben
public override String Ausgabe()
{
String resultat = base.Ausgabe();
resultat = resultat + ", Sitzplaetze: " + plaetze;
return resultat;
}
// überladen
public String Ausgabe(int mietTage, int km)
{
double preis = base.GesamtPreis(mietTage, km);
String resultat = " Mietpreis für " + mietTage +
" Tage: CHF " + preis;
return resultat;
}
}
24
Die Klasse LKW
class LKW : MietObjekt
{
private int nutzLast;
public LKW(String type, double tPreis, double kmPreis, int last)
: base(type, tPreis)
{
this.nutzLast = last;
this.kmPreis = kmPreis;
}
public override double GesamtPreis(int tage, int km)
{
return tagesMietPreis * tage + km * kmPreis;
}
25
Die Klasse LKW
// überschreiben
public override String Ausgabe()
{
String resultat = base.Ausgabe();
resultat = resultat + ", Nutzlast: "+nutzLast+"kg\n";
resultat = resultat + " Preis pro Km: CHF" + kmPreis;
return resultat;
}
// überladen
public String Ausgabe(int mietTage, int kmGefahren)
{
double preis = this.GesamtPreis(mietTage, kmGefahren);
String res = " Mietpreis für " + mietTage + " Miettage und ";
res = res + kmGefahren + " km: " + preis;
return res;
}
}
26
Herunterladen