Lektion 22 - Operator Overloading
Operatoren fuer eigene Klassen definieren
Operator Overloading bedeutet: Du legst fest, wie Operatoren wie +,
-, *, == oder [] bei deinen eigenen Klassen
funktionieren. Dadurch kann objektorientierter Code natuerlicher und lesbarer werden.
1. Was ist Operator Overloading?
Normalerweise kennst du Operatoren aus Zahlen oder Texten. In Dart kannst du bestimmte Operatoren aber auch fuer eigene Klassen definieren.
final a = 3 + 4; // int plus int
final b = 'Hallo ' + 'Dart'; // String plus String
final c = pointA + pointB; // eigener Operator fuer eigene Klasse
Wichtig: Du veraenderst nicht den Operator selbst. Du definierst nur, was der Operator fuer deine Klasse bedeuten soll.
2. Syntax in Dart
In Dart schreibst du Operatoren wie Methoden, aber mit dem Schluesselwort
operator.
Rueckgabetyp operator Symbol(Parameter) {
return Ergebnis;
}
class Score {
int value;
Score(this.value);
Score operator +(Score other) {
return Score(value + other.value);
}
}
other ist das Objekt rechts vom Operator. Bei a + b ist
a das aktuelle Objekt und b der Parameter.
3. Beispiel: Punkte addieren
Stell dir ein Lernsystem vor, in dem Aufgaben Punkte bringen. Zwei Punktwerte sollen addiert werden koennen.
class Score {
final int value;
Score(this.value);
Score operator +(Score other) {
return Score(value + other.value);
}
@override
String toString() {
return '$value Punkte';
}
}
void main() {
final homework = Score(20);
final quiz = Score(15);
final total = homework + quiz;
print(total); // 35 Punkte
}
Ohne Operator Overloading muesstest du zum Beispiel
homework.add(quiz) schreiben. Mit + liest es sich wie eine echte
Addition.
4. Operatoren sollen logisch bleiben
Operator Overloading ist nur gut, wenn die Bedeutung sofort nachvollziehbar ist.
+ sollte addieren, verbinden oder kombinieren. Es sollte nicht loeschen,
speichern oder etwas Ueberraschendes tun.
Vector + Vector addiert KoordinatenUser + User loescht einen AccountScore + Score addiert PunkteScore + Score startet eine AppMoney + Money addiert BetraegeMoney + Money sendet eine Rechnung5. Beispiel: Vector mit + und -
Bei mathematischen Klassen ist Operator Overloading besonders gut lesbar.
class Vector2 {
final double x;
final double y;
const Vector2(this.x, this.y);
Vector2 operator +(Vector2 other) {
return Vector2(x + other.x, y + other.y);
}
Vector2 operator -(Vector2 other) {
return Vector2(x - other.x, y - other.y);
}
@override
String toString() {
return 'Vector2($x, $y)';
}
}
void main() {
final start = Vector2(10, 5);
final movement = Vector2(3, -2);
print(start + movement); // Vector2(13, 3)
print(start - movement); // Vector2(7, 7)
}
6. Vergleich mit ==
Bei eigenen Klassen prueft == ohne Anpassung oft nicht das, was Lernende
erwarten. Zwei verschiedene Objekte mit gleichen Werten sind nicht automatisch gleich.
class UserId {
final int value;
const UserId(this.value);
@override
bool operator ==(Object other) {
return other is UserId && other.value == value;
}
@override
int get hashCode {
return value.hashCode;
}
}
Wenn du == ueberschreibst, solltest du auch hashCode ueberschreiben.
Das ist wichtig fuer Collections wie Set und Map.
7. Warum hashCode wichtig ist
Collections muessen Objekte schnell finden koennen. hashCode ist dafuer eine
Art Kurzkennung. Wenn zwei Objekte mit == gleich sind, muessen sie auch denselben
hashCode haben.
final first = UserId(7);
final second = UserId(7);
print(first == second); // true
Ohne passenden hashCode koennen Sets und Maps unerwartet reagieren.
8. Zugriff mit []
Der Index-Operator [] kann sinnvoll sein, wenn deine Klasse wie eine Sammlung
oder Liste wirken soll.
class LessonCollection {
final List<String> lessons;
LessonCollection(this.lessons);
String operator [](int index) {
return lessons[index];
}
}
void main() {
final course = LessonCollection(['Dart', 'Flutter']);
print(course[0]); // Dart
}
course[0] ruft intern deine Methode operator [] auf.
9. Wert setzen mit []=
Wenn eine Klasse Elemente veraendern darf, kannst du auch den Set-Operator definieren.
class LessonCollection {
final List<String> lessons;
LessonCollection(this.lessons);
String operator [](int index) {
return lessons[index];
}
void operator []=(int index, String value) {
lessons[index] = value;
}
}
void main() {
final course = LessonCollection(['Dart', 'Flutter']);
course[1] = 'Flutter Widgets';
print(course[1]);
}
10. Welche Operatoren kann man ueberladen?
Dart erlaubt Operator Overloading fuer eine feste Auswahl. Du kannst keine komplett neuen Operator-Symbole erfinden.
operator +
operator -
operator *
operator /
operator %
operator ==
operator <
operator <=
operator >
operator >=
operator []
operator []=
Operatoren wie && und || kannst du nicht fuer eigene Klassen
ueberladen.
11. Operator Overloading vs. Methode
Nicht alles braucht einen Operator. Manchmal ist eine normale Methode klarer.
scoreA + scoreBuser.save()moneyA == moneyBcourse.publish()12. Operator planen
Bevor du einen Operator programmierst, beschreibe erst, was links und rechts vom Operator steht und welches Ergebnis entstehen soll.
Operator + fuer Score:
Linker Score hat value
Rechter Score hat value
Addiere beide Werte
Erzeuge neuen Score mit Ergebnis
Gib neuen Score zurueck
Score operator +(Score other) {
return Score(value + other.value);
}
13. Typische Fehler
== ohne hashCodeSets und Maps koennen falsch reagieren.+ erwartet man oft ein neues Ergebnis.14. Aufgaben zu Operator Overloading
- Erstelle eine Klasse
Scoremitvalueund ueberlade+. - Erweitere
Scoreum-, damit Punkte abgezogen werden koennen. - Ueberschreibe
toString(), damitprint(score)lesbar ist. - Erstelle eine Klasse
Moneymitamountundcurrency. - Ueberlade
==undhashCodefuerMoney. - Schreibe zuerst eine kurze Planung fuer jeden Operator.
Planung fuer Money ==:
Wenn other kein Money ist:
Gib false zurueck
Wenn amount gleich other.amount ist
und currency gleich other.currency ist:
Gib true zurueck
Sonst:
Gib false zurueck
Weiter zu Entwicklerdokumentation