Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Overload zwischen Prozeduren und Funktionen
knittel - Di 19.02.13 00:37
Titel: Overload zwischen Prozeduren und Funktionen
Hallo allerseits,
führ ein 3D Programm, welches ich schreibe, hab ich mir eine Funktion geschrieben die einen Vektor normalisiert (nicht wundern ein Vektor ist hier vom Typ TMeleePosition (hat X,Y,Z als Werte))
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| function meNormalize(A: TMeleePosition): TMeleePosition; var length: glFloat; begin length := meLength(A); if (length = 0) then length := 1; result.X := A.X / length; result.Y := A.Y / length; result.Z := A.Z / length; end; |
Der Code ist auch nicht das Problem. Ich wollte mir nur zusätzlich noch eine Prozedur schreiben, die das selbe macht, deren Header aber so aussieht:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure meNormalize(var A: TMeleePosition); var length: glFloat; begin length := meLength(A); if (length = 0) then length := 1; A.X := A.X / length; A.Y := A.Y / length; A.Z := A.Z / length; end; |
Warum ich das möchte? Diese Funktion wird verdammt oft aufgerufen, und daher will ich immer die jeweils schnellere Version parat haben.
Mache ich soetwas: Vector := meNormalize(Vector); dann dauert das länger da er danach das result wieder in Vector schreiben muss.
Mache ich soetwas: Vector := meNormalize(meCrossProduct(VectorA, VectorB)); Dann wäre es ja blöd ich müsste dafür noch eine Variable einbauen, die dann erst normalisiert werden kann.
Daher wollte ich wissen ob ich mit einfach die beiden oben gezeigten Funktionen/Prozeduren mit overload ausstatten kann und dann nimmt er automatisch das richtige (das Problem ist ja, dass die beiden Funktionen die selben Parameter haben) oder muss ich eine der Funktionen umbennen?
Danke schon mal im vorraus.
WasWeißDennIch - Di 19.02.13 09:23
Überladen wird nicht funktionieren, da für den Compiler nicht immer eindeutig erkennbar ist, welche der beiden Varianten gemeint ist. IMO wirst Du um ein Umbenennen nicht herumkommen.
Tranx - Di 19.02.13 10:19
Das entscheidende bei der Überladung von Prozeduren udn Funktionen ist die Unterschiedlichkeit der Parameterliste. Das heißt im Klartext, dass Prozeduren mit gleichen Parameterlisten (und in diesem Zusammenhang ist Var keine Unterscheidung, da der Typ gefragt ist, und nicht die Art der Übertragung/Speicherung/Übergabe) nicht gegenseitig überlagert werden dürfen. Wie oben schon erwähnt, prüft der Compiler anhand des Typs der Parameter, welche Funktion/Prozedur genommen wird. Hier geht das nicht, da beide Parameterlisten vom Typ her gleich sind.
Blup - Di 19.02.13 10:50
Wenn man die Prozedur als Methode des Records definiert, ist die gleiche Bezeichnung möglich.
Allerdings muss der Aufruf dann trotzdem anders notiert werden.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| type TMeleePosition = record x,y,z: glFloat; procedure meNormalize; end;
function meNormalize(const A: TMeleePosition): TMeleePosition;
implementation
procedure TMeleePosition.meNormalize; var length: glFloat; begin length := meLength(A); if (length = 0) then Exit; X := X / length; Y := Y / length; Z := Z / length; end;
function meNormalize(const A: TMeleePosition): TMeleePosition; begin Result := A; Result.meNormalize; end;
Vector.meNormalize; Vector := meNormalize(meCrossProduct(VectorA, VectorB)); |
Mr_Emre_D - Di 19.02.13 10:52
Wie wärs hiermit?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| function meNormalize(var A: TMeleePosition; const Apply: Boolean = false): TMeleePosition; var length: glFloat; begin length := meLength(A); if (length = 0) then length := 1; Result.X := A.X / length; Result.Y := A.Y / length; Result.Z := A.Z / length; if Apply then A := Result; end; |
Damit kannst du die Funktion weiterhin so aufrufen
meNormalize(irgendEinVektor)
Zustätzlich kannst du nun auch angeben, ob die Berechnung übernommen werden soll
meNormalize(irgendEinVektor, true)
WasWeißDennIch - Di 19.02.13 11:22
knittel hat folgendes geschrieben : |
Warum ich das möchte? Diese Funktion wird verdammt oft aufgerufen, und daher will ich immer die jeweils schnellere Version parat haben.
Mache ich soetwas: Vector := meNormalize(Vector); dann dauert das länger da er danach das result wieder in Vector schreiben muss.
Mache ich soetwas: Vector := meNormalize(meCrossProduct(VectorA, VectorB)); Dann wäre es ja blöd ich müsste dafür noch eine Variable einbauen, die dann erst normalisiert werden kann. |
Mr_Emre_D hat folgendes geschrieben : |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| function meNormalize(var A: TMeleePosition; const Apply: Boolean = false): TMeleePosition; var length: glFloat; begin length := meLength(A); if (length = 0) then length := 1; Result.X := A.X / length; Result.Y := A.Y / length; Result.Z := A.Z / length; if Apply then A := Result; end; | |
Unter diesem Gesichtspunkt sind nun beide Nachteile vereint :mrgreen:
knittel - Di 19.02.13 13:46
Hallo nochmal,
erstmal vielen Dank für die vielen Antworten! Die Lösung von Blub gefällt mir zwar am besten, aber bei mir wirft er mir nen Compiler-Error entgegen beim starten (END expected but PROCEDURE found). Kann es sein, dass man Prozeduren für Records erst ab späteren Delphi Versionen nutzen kann (ich habe Delphi 7)? Ansonsten folge ich WasWeißDennIch's Rat und bennene die Prozedur um. Sollte aber kein Problem sein, wäre halt schön gewesen hätte es auch so funktioniert. :)
Martok - Di 19.02.13 15:16
knittel hat folgendes geschrieben : |
Kann es sein, dass man Prozeduren für Records erst ab späteren Delphi Versionen nutzen kann (ich habe Delphi 7)? |
Die Syntax wurde geändert, in D7 ist das noch getrennt in
object und
record, also hier:
Delphi-Quelltext
1: 2: 3: 4: 5:
| type TMeleePosition = object x,y,z: glFloat; procedure meNormalize; end; |
Tranx - Di 19.02.13 16:50
Also, es ist zwar eine Krücke, aber das funktioniert (Delphi 5):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:
| unit xxx;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type pVektor = ^Vektor; Vektor = Record X, Y : EXTENDED; end;
var
procedure Test(var v : Vektor); overload; function Test(v : pVektor) : Vektor; overload; procedure TueWas;
implementation {$R *.DFM}
procedure Test(var v : Vektor); begin v.X := v.X + 1.0; v.Y := v.y + 1.0; end;
function Test(v : pVektor) : Vektor; overload; begin v^.X := v^.X + 1.0; v^.Y := v^.Y + 1.0; Result := v^; end;
procedure TueWas; var v : Vektor; pv : pVektor; begin v.X := 10.0; v.Y := - 4.0; Test(v); v := Test(@v); end;
end. |
Wenn Du als Funktionswert der Funktion "Kreuzprodukt zweier Vektoren" nicht den Vektor, sonder den Zeiger auf einen Vektor (pVektor) übergibst, so kann der Compiler erkennen, welche beiden Funktionen zu nehmen sind. Denn pVektor und Vektor sind unterschiedlich.
Vielleicht hilft Dir das.
knittel - Di 19.02.13 17:27
Vielen Dank an Matrok und Tranx. Mir gefallen beide Lösungen, würde aber gern Martoks Lösung testen.
Dazu eine Frage: Was genau ist denn hier der Unterschied zwischen record und object? Muss ich bei object erst Speicherplatz reservieren oder ähnliches, oder kann man es genauso anwenden wir einen record?
Danke nochmal und sorry, dass euch ihr so löchere ;)
Martok - Di 19.02.13 17:50
knittel hat folgendes geschrieben : |
Was genau ist denn hier der Unterschied zwischen record und object? Muss ich bei object erst Speicherplatz reservieren oder ähnliches, oder kann man es genauso anwenden wir einen record? |
Im Endeffekt gibt's keinen mehr.
Object ist so ein Kompatibilitätszeug aus TurboPascal und stammt damit aus der Zeit vor
class. Dabei werden die Daten bei Zuweisungen immer kopiert und Methoden haben keinen Self-Pointer (wie bei Klassen), sondern sind relativ verdingst. Das Ganze ist seit Jahren deprecated, aber anscheinend ist Embadingsda mal aufgefallen dass man sowas ja doch öfter braucht und wurde dann als "record-mit-Methoden" wieder eingeführt, weil man deprecated-Markierungen ja nicht so einfach wieder loswird.
Der generierte Code ist komplett identisch.
Seit Delphi 2009 stimmt das so auch nicht mehr ganz, weil records da
noch mehr können [
http://docwiki.embarcadero.com/RADStudio/XE3/en/Structured_Types#Records_.28advanced.29], aber an der einfachen Verwendung ändert sich nix.
knittel hat folgendes geschrieben : |
Danke nochmal und sorry, dass euch ihr so löchere ;) |
Kein Problem, dafür ist das Forum ja da :zwinker:
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!