![]() |
Delphi-Version: XE2
Vektorklasse mit echten Operatoren
Hallo,
das Thema gibt es sicher schon, ich konnte es aber nicht finden. Irgendwo hab ich hier gesehen, wie man eine Klasse für Vektorrechnung so umsetzt, dass Operatoren wie +/-/x/... richtig interpretiert werden, sodass man nicht schreiben muss: cVektor := vadd(aVector, bVector) sondern einfach cVektor = aVektor + bVektor und die Funktion rechnet dann entsprechend. sorry, wenn es jetzt doch leicht zu finden ist und danke gruß cltom |
AW: Vektorklasse mit echten Operatoren
Das geht nur mit Records, nicht mit Klassen, und man nennt das
![]() |
AW: Vektorklasse mit echten Operatoren
Eine Beispiel-Implementierung um ein
![]()
Delphi-Quellcode:
var
Alpha: Extended; O, X, Y, Z: TVector2D; U, V, W: TPoint; begin Alpha := 0; // Drehwinkel O := TVector2D.New(200, 200); // Ortsvektor zum Drehpunkt X := TVector2D.New(-80, 0); // Dreieckspunkte relativ zum Drehpunkt Y := TVector2D.New(0, -80); Z := TVector2D.New(80, 0); { Das Dreieck erst drehen, dann um den Ortsvektor verschieben; denn: O + X.Rotated(Alpha) <> (O + X).Rotated(Alpha). } U := O + X.Rotated(Alpha); V := O + Y.Rotated(Alpha); W := O + Z.Rotated(Alpha); Image1.Canvas.Polygon([U, V, W]); end; |
AW: Vektorklasse mit echten Operatoren
Ich hatte sowas schon mal probeweise für zweidimensionale Vektoren implementiert, das aber später aus Performancegründen nicht weiter verfolgt. Im 3D-Bereich gibt es dann allerdings zwei Arten der Multiplikation zweier Vektoren. Leider geht das Overloading der Operatoren nicht so weit, daß man dort noch nach dem Ergebnistyp unterscheidet. In dem Fall würde das Kreuzprodukt dann wohl aus der Semantik rausfallen.
Delphi-Quellcode:
const
NativeFormat: TFormatSettings = (DecimalSeparator: '.'); type TVektor = record X, Y: Extended; class operator Add(A, B: TVektor): TVektor; class operator Divide(A: TVektor; B: Extended): TVektor; class operator Equal(A, B: TVektor): Boolean; class operator Explicit(A: TVektor): string; class operator Implicit(A: TVektor): string; class operator Multiply(A: Extended; B: TVektor): TVektor; class operator Multiply(A: TVektor; B: Extended): TVektor; class operator Multiply(A: TVektor; B: TVektor): Extended; class operator Negative(A: TVektor): TVektor; class operator NotEqual(A, B: TVektor): Boolean; class operator Positive(A: TVektor): TVektor; class operator Subtract(A, B: TVektor): TVektor; end; class operator TVektor.Add(A, B: TVektor): TVektor; begin result.X := A.X + B.X; result.Y := A.Y + B.Y; end; class operator TVektor.Divide(A: TVektor; B: Extended): TVektor; begin result.X := A.X / B; result.Y := A.Y / B; end; class operator TVektor.Equal(A, B: TVektor): Boolean; begin result := SameValue(A.X, B.X) and SameValue(A.Y, B.Y); end; class operator TVektor.Explicit(A: TVektor): string; begin result := Format('(%1.3f, %1.3f)', [A.X, A.Y], NativeFormat); end; class operator TVektor.Implicit(A: TVektor): string; begin result := string(A); end; class operator TVektor.Multiply(A: Extended; B: TVektor): TVektor; begin result.X := A * B.X; result.Y := A * B.Y; end; class operator TVektor.Multiply(A: TVektor; B: Extended): TVektor; begin result.X := A.X * B; result.Y := A.Y * B; end; class operator TVektor.Multiply(A, B: TVektor): Extended; begin result := A.X * B.X + A.Y * B.Y; end; class operator TVektor.Negative(A: TVektor): TVektor; begin result.X := -A.X; result.Y := -A.Y; end; class operator TVektor.NotEqual(A, B: TVektor): Boolean; begin result := not SameValue(A, B); end; class operator TVektor.Positive(A: TVektor): TVektor; begin result := A; end; class operator TVektor.Subtract(A, B: TVektor): TVektor; begin result.X := A.X - B.X; result.Y := A.Y - B.Y; end; |
AW: Vektorklasse mit echten Operatoren
Zitat:
|
AW: Vektorklasse mit echten Operatoren
Wie sieht es eigentlich mit dem "Nextgen"-Compiler aus? Da müsste doch für Klassen mittlerweile volle Operator-Überladung funktionieren, oder?
|
AW: Vektorklasse mit echten Operatoren
Zitat:
|
AW: Vektorklasse mit echten Operatoren
Ich hatte das Kreuzprodukt mal mit dem Divisionsoperator realisiert, da dieser bei Vektoren sonst keine sinnvolle Verwendung hat.
|
AW: Vektorklasse mit echten Operatoren
Zitat:
|
AW: Vektorklasse mit echten Operatoren
Zitat:
Delphi-Quellcode:
Allein für die erste "Addition" entsteht ein vom Programmierer nicht referenzierbares "Zwischenobjekt". Der Programmierer kann es nicht explizit freigeben und es liegt auf Ewig unbenutzt im Speicher.
var
obj1, obj2: TMyObject; begin obj2 := obj1 + obj1 + obj1; end; Deshalb gibt es im "alten" Delphi-Compiler keine Operator-Überladung für Klassen. Dachte ich. Mit ARC hat man dieses Problem ja nicht. Anscheinend habe ich sogar Recht: Zitat:
![]() Mann, gebt mir endlich den "Nextgen"-Compiler für Windows 8-) |
AW: Vektorklasse mit echten Operatoren
Zitat:
wenn die endlich mal meine Wünsche implementiert hätten, die seit Jahren im QC rumgammeln. Der Grund, warum es bei Klassen nicht geht/ging, liegt darin begründet, daß dort keine automatische Speicherverwaltung existiert.
Delphi-Quellcode:
Hier würden ja temporäre Variablen/Instanzen erstellt.
x := a * b + c;
// oder x := a + b + c; // [add] und selbst das einfache Nächste geht nicht x := a + b; - das Ergebnis von a*b und a+b - und das Ergebnis von t+c Aber keiner fühlt sich verantwortlich diese Instanzen freizugeben. Und es gibt noch ein paar Problemchen, denn es gibt kein Copy-Event, auf welches man per Klassenoperator reagieren kann. Bei
Delphi-Quellcode:
kann man mit Klassen und vorallem ohne Referenzzählung nichts richtig behandeln.
X := Y;
Ich hatte mal versucht Interfaces in den Operator-Record zu packen, aber das war eine Heiden Arbeit und so weit ich mich erinnere, gab es dennoch ein paar Problemchen. (wofür ich gerne das Copy-Event haben wollte) [add] ![]() |
AW: Vektorklasse mit echten Operatoren
Zitat:
Das kostet potenziell ein Vielfaches von dem Aufwand für die eigentliche Operation. Für größere Datenstrukturen (große Matrizen) könnte das egal sein, aber für kleine Vektoren ist das nichts. |
AW: Vektorklasse mit echten Operatoren
FastMM hat für kleine Speicherstücken eh fast immer schon einige Blöcke bereitwillig daliegen.
Ja, es dauert zwar immernoch ein "paar" Prozessortakte mehr, bis man sich einen freien Block rausgesucht und als belegt mariert hat, aber zum Glück ist das immernoch viel schneller, als es erst beim Windows zu beantragen. Selbst wenn das ml für Objekte/Interfaces implementiert ist, dann kann man für kleinere Strukturen immernoch die Records verwenden. :D |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:10 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz