SYTUACJACzy naprawdę potrzebne są konstruktory rekordów Delphi?
uczę „Więcej kodowania w Delphi” Nick Hodges, a on stosuje TFraction
rekord wyjaśnić przeciążanie operatorów. Pisałem ten sam rekord:
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;
oczywiście musiałem utworzyć konstruktor, ponieważ w Q (wymiernych) Muszę mieć mianownik, który nie jest równy zeru.
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
Ponieważ przeciążenia operatora zwrócić TFraction
, mam zamiar zdefiniować operację tak:
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;
Jak widać tutaj, jestem tworzenie tmp
, która jest zwracana z funkcji.
Kiedy czytam książkę Marco Cantu, on używany innego podejścia:
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;
Zrobiłem kilka testów, i widzę, że oba dają mi poprawny wynik, ale jest coś, że nie mogę zrozumieć. W pierwszym podejściu deklaruję tmp, a następnie wywołuję konstruktora, dzięki czemu mogę zwrócić TFraction
. W drugim podejściu nie robię niczego, ponieważ rekordy mają automatyczny konstruktor. Dokumentacja w rzeczywistości, mówi, że:
Records są skonstruowane automatycznie, przy użyciu domyślnego no dwuargoomentowe konstruktora, ale zajęcia muszą być wyraźnie skonstruowana. Ponieważ rekordy mają domyślny konstruktor bezargumentowy, każdy zdefiniowany przez użytkownika konstruktor rekordów musi mieć jeden lub więcej parametrów.
Tutaj mam zdefiniowany przez użytkownika konstruktor rekordów. A więc:
Czy wywołanie konstruktora na
tmp
pierwszego podejścia nie jest potrzebne? Jeśli chcę zadzwonić pod numerReduce
(co jest procedurą), muszę utworzyć zmienną. Czy urządzenieResult
właśnie zwróci kopiętmp
bez tworzenia?W drugim podejściu są
Result.aNumerator
iResult.aDenominator
parametry automatycznego utworzonego konstruktora?
W przypadku niepowiązanych notatek, zwykle normalną praktyką jest użycie 'F' jako przedrostka dla prywatnych pól w klasie oraz przedrostek' A' dla parametrów metody (których używasz). W Delphi wszystko jest w porządku, ale najwyraźniej w Łazarzu to się nie skomplikuje. –
Ok, dziękuję, nie wiedziałem, używam a dla parametrów i zmiennych. Zmienię nawyk! –
@Jerry Co masz na myśli. FPC nie wymusza reguł konwencji nazewnictwa. –