3.11 Benutzerdefinierte Operatoren 

Die Gründe dafür, selbst Operatoren für Datentypen zu definieren, lassen sich in zwei Gruppen unterteilen:
- Bequemlichkeit: Der Quelltext kann kürzer formuliert werden.
- Implizite Nutzung: Die Operatoren CType, IsTrue und IsFalse werden gegebenenfalls von Code aufgerufen, der vom Compiler automatisch erstellt wird.
Hinweis |
Ein einmal definierter Operator kann nicht mehr geändert werden (Polymorphie für klassengebundene Methoden gibt es nicht in Visual Basic, siehe Abschnitt 3.14, »Polymorphie«). |
3.11.1 Prinzip 

Tabelle 3.19 teilt die benutzerdefinierbaren Operatoren in fünf Gruppen ein.
Anwendungsbereich | Operator |
Arithmetik |
+ – * / \ ^ Mod << >> And Or Xor (+- auch unär) |
Vergleich |
= <> > < >= <= Like |
Logik |
Not IsTrue IsFalse And Or Xor |
Zeichenketten |
& |
Typumwandlung |
CType |
Zwei Arten von Operatoren sind nicht neu definierbar, können aber zum Teil auf benutzerdefinierte Operatoren zurückgreifen:
- = selbst kann nicht neu definiert werden, aber alle zusammengesetzten Zuweisungsoperatoren nutzen passende benutzerdefinierte Operatoren für den Nicht-Zuweisungsteil des Operators.
- AndAlso und OrElse selbst können nicht neu definiert werden, aber sie nutzen passende benutzerdefinierte Operatoren von And, Or, IsTrue und IsFalse.
Alle Parameter der benutzerdefinierten Operatoren werden mit ByVal als Wert übergeben. Die Syntax der Definition lautet (optionale Teile stehen in eckigen Klammern und kursive Teile müssen Sie Ihren Bedürfnissen anpassen):
Public Shared [<Modifikatoren>] Operator oper(<Parameter>) As Typ |
Hinweis |
Mindestens einer der Operanden (bei Typumwandlungen: oder der Rückgabewert) muss vom Typ der definierenden Klasse sein. |
Tabelle 3.20 zeigt die erlaubten Modifikatoren.
Art | Beschreibung |
Redefinition |
Art des Ersatzes oder Zwangs zu einer Definition (siehe Abschnitt 3.13, »Vererbung« und Abschnitt 3.3.4, »Überladung (Overloads)«) |
Typumwandlung |
Explizit oder implizit (siehe Abschnitt 3.11.4, »Typumwandlung mit CType: Widening und Narrowing«) |
Für jeden benutzerdefinierten Operator fügt der Compiler automatisch eine öffentliche Methode hinzu, deren Name mit op_ beginnt. In Tabelle 3.21 ist dieser Namensteil weggelassen. Die Methodennamen für die Operatoren Not, And, Or und Xor sind gleich für logische und bitweise Operationen. Beim Zusammenspiel mit anderen Programmiersprachen werden bei konkurrierenden logischen und bitweisen Operatoren die logischen ignoriert. Analog wird bei Bitschiebeoperatoren gegebenenfalls nur die vorzeichenbehaftete Version berücksichtigt. Anderen Programmiersprachen wird die ganzzahlige Division \ als normale Division / mit korrekter Bedeutung zur Verfügung gestellt. Statt des Operators kann auch die korrespondierende Methode verwendet werden.
Hinweis |
Die alleinige Definition einer Operatormethode reicht nicht aus, um einen Operator verwenden zu können. |
Methode op_ | Methode op_ | Methode op_ | |||
+ |
Addition |
<< |
LeftShift |
= |
Equality |
+ |
UnaryPlus |
>> |
RightShift |
<> |
Inequality |
- |
Subtraction |
And |
BitwiseAnd |
< |
LessThan |
- |
UnaryNegation |
Or |
BitwiseOr |
> |
GreaterThan |
* |
Multiply |
Xor |
ExclusiveOr |
<= |
LessThanOrEqual |
/ |
Division |
Not |
OnesComplement |
>= |
GreaterThanOrEqual |
^ |
Exponent |
\ |
IntegerDivision |
Like |
Like |
Mod |
Modulus |
& |
Concatenate |
||
Widening CType |
Implicit |
IsTrue |
True |
||
Narrowing CType |
Explicit |
IsFalse |
False |
Hinweis |
Sie müssen selbst darauf achten, dass ein Operator und der Typ seines Rückgabewerts eine sinnvolle Kombination ergeben. Bei IsTrue und IsFalse ist der Typ der Rückgabe zwingend Boolean. |
Schauen wir uns ein Beispiel an. Das folgende Codefragment definiert eine Matrix mit Fließkommazahlen, die mit dem Stringverkettungsoperator & komfortabel ausgegeben werden kann. Die Methode Append() übernimmt die Formatierung. Die Variable ein bestimmt die nötige Einrückung folgender Zeilen, indem sie die bisherige Ausgabe str mithilfe regulärer Ausdrücke durch Leerzeichen ersetzt. PadLeft() sorgt dafür, dass alle Zahlen einer Spalte untereinander stehen. Der Operator & erlaubt durch die zwei Definitionen, dass die Matrix links oder rechts einer Zeichenkette stehen darf.
'...\Klassendesign\Operatoren\Zeichenketten.vb |
Option Strict On
Namespace Klassendesign
Class Matrix
Private val(,) As Double
Sub New(ByVal val(,) As Double)
Me.val = val
End Sub
Function Append(ByVal str As String) As String
Dim ein As String = _
Text.RegularExpressions.Regex.Replace(str, ".", " ")
For row As Int32 = 0 To val.GetUpperBound(0)
For col As Int32 = 0 To val.GetUpperBound(1)
str += val(row, col).ToString("##0.0").PadLeft(6)
Next
If row < val.GetUpperBound(0) Then _
str += Environment.NewLine & ein
Next
Return str
End Function
Public Shared Operator &(ByVal lhs As Matrix, ByVal rhs As String) _
As String
Return lhs.Append(rhs)
End Operator
Public Shared Operator &(ByVal lhs As String, ByVal rhs As Matrix) _
As String
Return rhs.Append(lhs)
End Operator
End Class
...
End Namespace
Eine Matrix auszugeben wird damit sehr einfach:
'...\Klassendesign\Operatoren\Zeichenketten.vb |
Option Strict On
Namespace Klassendesign
...
Module Zeichenketten
Sub Test()
Dim M As Matrix = New Matrix(New Double(,) _
{{17.8, –25, 34.1},{9.1, 73.4, 82},{0, –3.4, –5.1}})
Console.WriteLine("Matrix " & M & " und mehr ...")
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe zeigt die Werte zweidimensional und fügt sie nahtlos ein.
Matrix 17.8 –25.0 34.1
9.1 73.4 82.0
0.0 –3.4 –5.1 und mehr ...
3.11.2 Überladung 

Bei der Definition eines Operators sollten Sie darauf achten, dass alle für Sie interessanten Parametertypen erfasst werden. Der Fall, der einem als Erstes in den Sinn kommt, hat als Parameter nur Werte vom Typ der definierenden Klasse. Aber auch die Kombination mit Werten eines anderen Typs ist häufig sinnvoll. Beispielhaft zeigt das nächste Codefragment nicht nur die Addition zweier Vektoren, sondern auch die Addition eines Vektors und eines Skalars (Zahl), der links oder rechts vom Vektor stehen darf. Insgesamt werden also drei Definitionen des Operators gebraucht. Um den Quelltext kurz zu halten, sind Überprüfungen auf Nullreferenzen und gleiche Länge der Vektoren weggelassen.
'...\Klassendesign\Operatoren\Ueberladung.vb |
Option Strict On
Namespace Klassendesign
Class Vek
Private val() As Short
Sub New(ByVal val() As Short)
Me.val = val
End Sub
Shared Function Add(ByVal v1() As Short, ByVal v2() As Short) As Short()
Dim res() As Short = CType(v1.Clone(), Short())
Dim val(v1.Length – 1) As Short
For no As Integer = 0 To v1.Length – 1
val(no) = v1(no) + v2(Math.Min(no, v2.Length – 1))
Next
Return val
End Function
Function ToString() As String
Dim str As String = "|"
For Each d As Double In val : str += d & "|" : Next
Return str
End Function
Public Shared Operator +(ByVal lhs As Vek, ByVal rhs As Vek) As Vek
Return New Vek(Add(lhs.val, rhs.val))
End Operator
Public Shared Operator +(ByVal lhs As Vek, ByVal rhs As Short) As Vek
Return New Vek(Add(lhs.val, New Short() {rhs}))
End Operator
Public Shared Operator +(ByVal lhs As Short, ByVal rhs As Vek) As Vek
Return rhs + lhs
End Operator
End Class
...
End Namespace
Der Plus-Operator lässt sich nun ganz normal verwenden:
'...\Klassendesign\Operatoren\Ueberladung.vb |
Option Strict On
Namespace Klassendesign
...
Module Überladung
Sub Test()
Dim V As Vek = New Vek(New Short() {17, –25, 34})
Console.WriteLine("V {0}", V.ToString())
Console.WriteLine("V+V {0}", (V + V).ToString())
Console.WriteLine("V+3 {0}", (V + 3).ToString())
Console.WriteLine("3+V {0}", (3 + V).ToString())
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe bestätigt die richtige Arbeitsweise des Operators:
V |17|-25|34|
V+V |34|-50|68|
V+3 |20|-22|37|
3+V |20|-22|37|
Hinweis |
Bei nullbaren Werttypen werden gegebenenfalls auch die korrespondierenden nicht-nullbaren Versionen einer Operatordefinition berücksichtigt. Diese Typen werden in Abschnitt 4.5, »Werttypen mit dem Wert Nothing«, beschrieben. |
3.11.3 Vergleich 

Im Gegensatz zu vielen anderen Operatoren müssen korrespondierende Vergleichsoperationen gemeinsam überladen werden.
-
- = und <>
-
- > und <
-
- >= und <=
Im folgenden Beispiel wird die Länge eines Ländernamens stärker gewichtet als die alphabetische Reihenfolge: Kurze Namen erscheinen vor langen. Es wird nur ein Operator explizit kodiert, der entgegengesetzte Operator (das Antonym) ruft die Operatormethode auf und negiert das Ergebnis. Das garantiert, dass sich die gegensätzlichen Operatoren exakt ergänzen.
'...\Klassendesign\Operatoren\Vergleich.vb |
Option Strict On
Namespace Klassendesign
Class Land
Private name As String
Sub New(ByVal name As String)
Me.name = name
End Sub
Public Shared Operator <(ByVal l As Land, ByVal r As Land) As Boolean
Return l.name.Length <= r.name.Length AndAlso l.name < r.name
End Operator
Public Shared Operator >(ByVal l As Land, ByVal r As Land) As Boolean
Return Not op_LessThan(l, r) ' = Not l < r
End Operator
Shared Sub Test()
Dim L1 As Land = New Land("Finnland")
Dim L2 As Land = New Land("Island")
Dim L3 As Land = New Land("Schweden")
Console.WriteLine("{0}-{1}-{2}", L1.name, L2.name, L3.name)
Console.WriteLine("Namen 1<2: {0}", L1.name < L2.name)
Console.WriteLine("Namen 1<3: {0}", L1.name < L3.name)
Console.WriteLine("Länder 1<2: {0}", L1 < L2)
Console.WriteLine("Länder 1<3: {0}", L1 < L3)
Console.ReadLine()
End Sub
End Class
End Namespace
3.11.4 Typumwandlung mit CType: Widening und Narrowing 

Umwandlungen im weiteren Sinne begegnen uns oft im täglichen Leben. Wenn wir zum Beispiel im Fischladen eigentlich Fisch kaufen wollten, der Laden aber geschlossen ist und wir dennoch nicht unverrichteter Dinge nach Hause gehen wollen, gibt es zwei Möglichkeiten: Entweder begnügen wir uns mit einer Fischdose aus dem Supermarkt, oder wir gehen im Restaurant essen. In Hinblick auf das geplante Essen ist der Umstieg auf ein Restaurant ohne Verlust möglich, während die Dosenvariante die Qualität des Essens mindert. In der Softwaretechnik stehen wir manchmal vor ähnlichen Problemen. Erwartet eine Funktion eine ganze Zahl und soll eine Fließkommazahl als Parameter verwendet werden, können wir diese explizit mittels des Operators CType vor dem Aufruf unter Verlust der Nachkommastellen umwandeln (entspricht der Fischdose). Die andere Richtung, von der ganzen Zahl zur Fließkommazahl, ist verlustfrei möglich und wird auch oft gebraucht. Normalerweise machen wir uns darüber keine Gedanken, da die Umwandlung implizit (automatisch) erfolgt.
Bei der Definition von Konvertierungsoperatoren mit CType ist Folgendes zu beachten:
- Entweder der Start- oder der Zieltyp muss mit der Klasse übereinstimmen, in der der Operator definiert ist.
- Widening CType beschreibt eine implizite Konvertierung, die der Compiler automatisch verwendet.
- Narrowing CType beschreibt eine explizite Konvertierung, die expressis verbis im Quelltext stehen muss.
- Operatoren müssen sich durch mehr als nur Narrowing oder Widening unterscheiden.
- Konvertierungen, die Ausnahmen auslösen oder verlustbehaftet sein können, sollten mit Narrowing als explizit gekennzeichnet werden.
Hinweis |
Der Konvertierungsoperator CType ist die einzige Stelle, wo der Typ des Rückgabewerts Teil der Signatur ist. |
Das nächste Codefragment zeigt als Beispiel eine Autovermietung, bei der zwei Kunden bestellen. Zurzeit sind nur einige Ford Mondeo verfügbar, was sich in der Bestellmethode ausdrückt, die nur diesen Wagentyp entgegennimmt. Der erste Kunde bestellt mit einem Maybach ein teures Auto. Da ein Mondeo weniger Komfort bedeutet, muss durch eine explizite Umwandlung mit CType die Bestellung ermöglicht werden. Demgegenüber bestellt der zweite Kunde eine Ente. Der Vermieter kann dem Kunden ohne Weiteres einen Mondeo geben, da dieser hochwertiger als das bestellte Auto ist. Die Umwandlung erfolgt implizit beim Aufruf der Bestellmethode. Ob Sie die Typkonvertierungen auf zwei Klassen verteilen oder nicht, ist Geschmackssache. Wichtig ist, dass Sie dieselbe Konvertierung nicht durch zwei Klassen doppelt zur Verfügung stellen (die vom Compiler generierte Fehlermeldung ist nicht sehr aussagekräftig).
'...\Klassendesign\Operatoren\Konvertierungen.vb |
Option Strict On
Namespace Klassendesign
Class Ente : End Class
Class Maybach
Public Shared Narrowing Operator CType(ByVal auto As Maybach) As Mondeo
Console.Write("mit Rückerstattung ")
Return New Mondeo() 'um es einfach zu halten
End Operator
End Class
Class Mondeo
Public Shared Widening Operator CType(ByVal auto As Ente) As Mondeo
Console.Write("auf Kosten des Hauses ")
Return New Mondeo() 'um es einfach zu halten
End Operator
End Class
Module Autovermietung
Sub Bestellen(ByVal auto As Mondeo)
Console.WriteLine("Mondeo erhalten.")
End Sub
Sub Test()
Console.Write("Maybach bestellt und ")
Bestellen(CType(New Maybach(), Mondeo)) 'explizit – Narrowing
Console.Write("Ente bestellt und ")
Bestellen(New Ente()) 'implizit – Widening
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe »mit Rückerstattung« zeigt, dass für den ersten Kunden die Konvertierung mit Narrowing verwendet wurde, während beim zweiten Kunden die Widening-Variante »auf Kosten des Hauses« ausgibt.
Maybach bestellt und mit Rückerstattung Mondeo erhalten.
Ente bestellt und auf Kosten des Hauses Mondeo erhalten.
Eine Stolperfalle gibt es bei einer For Each-Schleife. Sie nutzt ausnahmsweise auch explizite Konvertierungen automatisch. Das folgende Codefragment nutzt die einzig vorhandene Konvertierung. Sie ist explizit.
'...\Klassendesign\Operatoren\ForEach.vb |
Option Strict On
Namespace Klassendesign
Class Zahl
Public Shared Narrowing Operator CType(ByVal f As Zahl) As Short
Return 0 'um es einfach zu halten
End Operator
End Class
Module ForEach
Sub Test()
For Each a As Short In New Zahl() {New Zahl()}
Console.Write(a & " ")
Next
Console.ReadLine()
End Sub
End Module
End Namespace
3.11.5 Wahrheitswerte: IsTrue und IsFalse 

Ob ein Wert als Wahrheitswert betrachtet wird, hängt davon ab, ob er eines der folgenden Kriterien erfüllt, wobei das erste zutreffende Kriterium genommen wird (Boolean? ist auch erlaubt, siehe Abschnitt 4.5, »Werttypen mit dem Wert Nothing«):
- Der Wert ist schon Boolean.
- Der Wert kann implizit in Boolean konvertiert werden.
- Der Wert definiert die Pseudooperatoren IsTrue und IsFalse.
Möchten Sie die letzte Variante wählen, ist Folgendes zu beachten:
- IsTrue und IsFalse müssen zusammen überladen werden.
- Boolean ist zwingend als Typ der Rückgabe zu verwenden (Boolean? geht nicht).
- Zur Benutzung von AndAlso und OrElse müssen And und Or so definiert sein, dass beide Parameter und das Ergebnis vom Typ der definierenden Klasse sind (natürlich können zusätzlich weitere Signaturen definiert sein).
Das folgende Codefragment zeigt eine Klasse Ort, die die Operatoren IsTrue, IsFalse, Or und And definiert. Jeder der Operatoren macht sich beim Aufruf durch eine Konsolenausgabe bemerkbar, um zu prüfen, ob und in welcher Reihenfolge die Operatoren angesprochen werden. Die Boolean-Operatoren geben außerdem an, welches Objekt (erster Buchstabe) mit welchem Ergebnis (J oder N) gerade getestet wird. Bei den Orten interessieren hier die Temperaturen, sodass »Kuba« als »wahr« und »Island« als »falsch« angesehen werden.
'...\Klassendesign\Operatoren\Wahrheitswerte.vb |
Option Strict On
Namespace Klassendesign
Class Ort
Friend ReadOnly wo As String
Sub New(ByVal wo As String)
Me.wo = wo
End Sub
Public Shared Operator IsTrue(ByVal o As Ort) As Boolean
Console.Write(o.wo(0) & ":IsTrue :" & If(o.wo = "Kuba", "J ", "N "))
Return o.wo = "Kuba"
End Operator
Public Shared Operator IsFalse(ByVal o As Ort) As Boolean
Console.Write(o.wo(0) & ":IsFalse:" & If(o.wo = "Island", "J ", "N "))
Return o.wo = "Island"
End Operator
Public Shared Operator Or(ByVal a As Ort, ByVal b As Ort) As Ort
Console.Write("Op_| ")
Return If(a.wo = "Kuba" Or b.wo = "Kuba", a, b)
End Operator
Public Shared Operator And(ByVal a As Ort, ByVal b As Ort) As Ort
Console.Write("Op_& ")
Return If(a.wo <> "Island" And b.wo <> "Island", a, b)
End Operator
End Class
...
End Namespace
Der Test der Operaratoren erfolgt mit einer Liste von Länderpaaren, die in einem Array von Länderarrays abgelegt wird. Die Art der Erzeugung ist hier unwichtig; die Syntax wird in Abschnitt 6.4, »LINQ« erläutert. Der Test innerhalb der Schleife spricht zuerst im ersten Argument der beiden ersten If-Operatoren die Objekte direkt als Wahrheitswerte an. Danach folgt der Test der Logikoperatoren.
'...\Klassendesign\Operatoren\Wahrheitswerte.vb |
Option Strict On
Namespace Klassendesign
...
Module Wahrheitswerte
Sub out(ByVal str As String, ByVal newline As Boolean)
Console.Write(str.PadRight(16) & If(newline, Environment.NewLine, ""))
End Sub
Sub Test()
Const h As String = "warm"
Const k As String = "kalt"
Dim wo() As Ort = New Ort() _
{New Ort("Kuba"), New Ort("Island"), New Ort("Japan")}
'Kombination jeder mit jedem: cross join
Dim orte()() As Ort = _
(From o1 In wo From o2 In wo Select New Ort() {o1, o2}).ToArray()
For Each o() As Ort In orte
out((o(0).wo & " ist " & If(o(0), h, k)).PadRight(21), False)
out((o(1).wo & " ist " & If(o(1), h, k)).PadRight(21), True)
out("Or ist " & If(o(0) Or o(1), h, k), False)
out("OrElse ist " & If(o(0) OrElse o(1), h, k), True)
out("And ist " & If(o(0) And o(1), h, k), False)
out("AndAlso ist " & If(o(0) AndAlso o(1), h, k), True)
Console.WriteLine()
Next
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe zeigt das Verhalten der Operatoren:
- Normale Logikoperatoren (And und Or): Der Operator wird aufgerufen, und das Ergebnis, das vom Typ der Klasse (Ort) ist, wird mit IsTrue auf den Wahrheitsgehalt getestet.
- Kurzschlussoperatoren (AndAlso und OrElse): Der erste Operand wird bei AndAlso mit IsFalse und bei OrElse mit IsTrue getestet. Steht das Ergebnis fest, wird (warum auch immer) der Operand erneut getestet; ist das Ergebnis noch unbestimmt, wird der korrespondierende normale Logikoperator aufgerufen.
K:IsTrue :J Kuba ist warm K:IsTrue :J Kuba ist warm
Op_| K:IsTrue :J Or ist warm K:IsTrue :J K:IsTrue :J OrElse ist warm
Op_& K:IsTrue :J And ist warm K:IsFalse:N Op_& K:IsTrue :J AndAlso ist warm
K:IsTrue :J Kuba ist warm I:IsTrue :N Island ist kalt
Op_| K:IsTrue :J Or ist warm K:IsTrue :J K:IsTrue :J OrElse ist warm
Op_& I:IsTrue :N And ist kalt K:IsFalse:N Op_& I:IsTrue :N AndAlso ist kalt
K:IsTrue :J Kuba ist warm J:IsTrue :N Japan ist kalt
Op_| K:IsTrue :J Or ist warm K:IsTrue :J K:IsTrue :J OrElse ist warm
Op_& K:IsTrue :J And ist warm K:IsFalse:N Op_& K:IsTrue :J AndAlso ist warm
I:IsTrue :N Island ist kalt K:IsTrue :J Kuba ist warm
Op_| I:IsTrue :N Or ist kalt I:IsTrue :N Op_| I:IsTrue :N OrElse ist kalt
Op_& K:IsTrue :J And ist warm I:IsFalse:J I:IsTrue :N AndAlso ist kalt
I:IsTrue :N Island ist kalt I:IsTrue :N Island ist kalt
Op_| I:IsTrue :N Or ist kalt I:IsTrue :N Op_| I:IsTrue :N OrElse ist kalt
Op_& I:IsTrue :N And ist kalt I:IsFalse:J I:IsTrue :N AndAlso ist kalt
I:IsTrue :N Island ist kalt J:IsTrue :N Japan ist kalt
Op_| J:IsTrue :N Or ist kalt I:IsTrue :N Op_| J:IsTrue :N OrElse ist kalt
Op_& J:IsTrue :N And ist kalt I:IsFalse:J I:IsTrue :N AndAlso ist kalt
J:IsTrue :N Japan ist kalt K:IsTrue :J Kuba ist warm
Op_| J:IsTrue :N Or ist kalt J:IsTrue :N Op_| J:IsTrue :N OrElse ist kalt
Op_& J:IsTrue :N And ist kalt J:IsFalse:N Op_& J:IsTrue :N AndAlso ist kalt
J:IsTrue :N Japan ist kalt I:IsTrue :N Island ist kalt
Op_| I:IsTrue :N Or ist kalt J:IsTrue :N Op_| I:IsTrue :N OrElse ist kalt
Op_& I:IsTrue :N And ist kalt J:IsFalse:N Op_& I:IsTrue :N AndAlso ist kalt
J:IsTrue :N Japan ist kalt J:IsTrue :N Japan ist kalt
Op_| J:IsTrue :N Or ist kalt J:IsTrue :N Op_| J:IsTrue :N OrElse ist kalt
Op_& J:IsTrue :N And ist kalt J:IsFalse:N Op_& J:IsTrue :N AndAlso ist kalt
3.11.6 Grafikbibliothek: Addition und Umwandlung von Rechtecken 

In diesem Abschnitt erweitern wir die in Abschnitt 3.1.12, »Grafikbibliothek: Beispiel für Kapitel 3 und 4«, eingeführte und zuletzt in Abschnitt 3.10.6, »Grafikbibliothek: Größenänderungen von Rechtecken überwachen«, erweiterte Grafikanwendung. Der neu hinzukommende Additionsoperator erzeugt ein Rechteck, das die beiden Operanden umschließt. Bei der Typkonvertierung von Double nach Rechteck wird die Zahl als Fläche aufgefasst und ein flächengleiches Rechteck erzeugt.
'...\Klassendesign\Graphik\Operatoren.vb |
Option Explicit On
Namespace Klassendesign
Partial Public Class Rechteck
Shared Operator +(ByVal r1 As Rechteck,ByVal r2 As Rechteck) As Rechteck
Return New Rechteck(Math.Max(r1.a, r2.a), Math.Max(r1.b, r2.b))
End Operator
Shared Widening Operator CType(ByVal fläche As Double) As Rechteck
Return New Rechteck(Math.Sqrt(fläche), Math.Sqrt(fläche))
End Operator
End Class
End Namespace
Zum Test werden zwei Rechtecke erzeugt – das zweite durch die implizite Anwendung der definierten Typumwandlung. Danach werden die beiden Rechtecke mittels des neu definierten Additionsoperators zusammengefasst. Schließlich werden die Größen aller drei Rechtecke ausgegeben.
'...\Klassendesign\Zeichner\Operatoren.vb |
Option Explicit On
Namespace Klassendesign
Partial Class Zeichner
Sub Operatoren()
Dim r1 As New Rechteck(9, 2)
Dim r2 As Rechteck = 49
Dim r3 As Rechteck = r1 + r2
r1.Größe() : r2.Größe() : r3.Größe()
End Sub
End Class
End Namespace
Zur Kontrolle sehen Sie hier die Ausgabe der Methode Operatoren():
Dimension des Rechtecks: 9x2
Dimension des Rechtecks: 7x7
Dimension des Rechtecks: 9x7
Die nächste Erweiterung erfolgt in Abschnitt 3.13.9, »Grafikbibliothek: neue Vielecke«.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.