SITUATIONWerden Delphi-Record-Konstruktoren wirklich benötigt?
I "Mehr Coding in Delphi" von Nick Hodges studiere, und er wird mit einem TFraction
Rekordüberladen von Operatoren zu erklären. Ich habe bei mir selbst diesen Satz geschrieben:
type
TFraction = record
strict private
aNumerator: integer;
aDenominator: integer;
function GCD(a, b: integer): integer;
public
constructor Create(aNumerator: integer; aDenominator: integer);
procedure Reduce;
class operator Add(fraction1, fraction2: TFraction): TFraction;
class operator Subtract(fraction1, fraction2: TFraction): TFraction;
//... implicit, explicit, multiply...
property Numerator: integer read aNumerator;
property Denominator: integer read aDenominator;
end;
Natürlich hatte ich einen Konstruktor zu erstellen, da in Q (rationals) Ich muss einen Nenner haben, die nicht gleich Null ist.
constructor TFraction.Create(aNumerator, aDenominator: integer);
begin
if (aDenominator = 0) then
begin
raise Exception.Create('Denominator cannot be zero in rationals!');
end;
if ((aNumerator < 0) or (aDenominator < 0)) then
begin
Self.aNumerator := -aNumerator;
Self.aDenominator := -aDenominator;
end
else
begin
Self.aNumerator := aNumerator;
Self.aDenominator := aDenominator;
end;
end;
PROBLEM
Da die Betreiber Überlastungen eine TFraction
zurückkehren, werde ich eine Operation wie folgt definieren:
class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction;
var
tmp: TFraction;
begin
//simple algorithm of the sum
tmp := TFraction.Create(fraction1.Numerator*fraction2.Denominator+fraction1.Denominator*fraction2.Numerator, fraction1.Denominator*fraction2.Denominator);
tmp.Reduce;
//return the result
Result := tmp;
end;
Wie man hier sehen kann, ich bin Erstellen einer tmp
, die von der Funktion zurückgegeben wird.
Als ich Marco Cantu Buch gelesen, benutzte er einen anderen Ansatz:
class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction;
begin
Result.aNumerator := (fraction1.Numerator*fraction2.Denominator+fraction1.Denominator*fraction2.Numerator);
Result.aDenominator := fraction1.Denominator*fraction2.Denominator;
end;
Ich habe einige Tests gemacht, und ich sehe, dass beide geben mir das richtige Ergebnis, aber es ist etwas, das ich nicht verstehen kann. Im ersten Ansatz deklariere ich tmp und dann rufe ich den Konstruktor, damit ich eine TFraction
zurückgeben kann. Im zweiten Ansatz erstelle ich nichts, weil Datensätze einen automatischen Konstruktor haben. Die Dokumentation in der Tat sagt, dass:
Datensätze werden automatisch aufgebaut, unter Verwendung eines Standard-No-Argument Konstruktor, sondern Klassen explizit konstruiert werden müssen. Da Datensätze einen Standardkonstruktor ohne Argumente haben, muss jeder benutzerdefinierte Datensatzkonstruktor einen oder mehrere Parameter haben.
Hier habe ich einen benutzerdefinierten Datensatz Konstruktor. Also:
Ist der Konstruktoraufruf auf
tmp
des ersten Ansatz nicht benötigt? Wenn ichReduce
aufrufen möchte (was eine Prozedur ist), muss ich eine Variable erstellen. Gibt dieResult
gerade eine Kopie vontmp
zurück, ohne etwas zu erstellen?Im zweiten Ansatz, sind
Result.aNumerator
undResult.aDenominator
die Parameter des automatisch erstellten Konstruktors?
auf einer nicht verwandte Notiz, es ist in der Regel normale Praxis 'F' als Präfix für private Felder in einer Klasse und der Präfix' A' für Methodenparameter zu verwenden (die Sie verwenden). In Delphi ist es in Ordnung, aber anscheinend, in Lazarus, würde das nicht kompilieren. –
Ok danke ich wusste nicht, ich verwende ein für Parameter und Variablen. Ich werde meine Gewohnheit ändern! –
@Jerry Was meinst du? FPC erzwingt keine Regeln für Namenskonventionen. –