СИТУАЦИЯ
Я изучаю «Больше кодирования в Delphi» Ника Ходжеса, и он использует запись TFraction
для объяснения перегрузки оператора. Я сам написал эту запись:
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;
Конечно, мне пришлось создать конструктор, потому что в Q (рациональные числа) у меня должен быть знаменатель, не равный нулю.
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;
ПРОБЛЕМА
Поскольку перегрузки оператора возвращают TFraction
, я собираюсь определить такую операцию:
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;
Как вы можете видеть здесь, я создаю tmp
, который возвращается функцией.
Когда я читал книгу Марко Канту, он использовал другой подход:
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;
Я провел несколько тестов и вижу, что оба дают правильный результат, но есть кое-что, чего я не могу понять. В первом подходе я объявляю tmp, а затем вызываю конструктор, чтобы я мог вернуть TFraction
. Во втором подходе я ничего не создаю, потому что у записей есть автоматический конструктор. В документации, по сути, сказано, что:
Записи создаются автоматически с использованием конструктора без аргументов по умолчанию, но классы должны быть созданы явно. Поскольку записи имеют конструктор без аргументов по умолчанию, любой определяемый пользователем конструктор записи должен иметь один или несколько параметров.
Здесь у меня есть определяемый пользователем конструктор записи. Так:
Не нужен ли вызов конструктора для
tmp
первого подхода? Если я хочу вызватьReduce
(который является процедурой), мне нужно создать переменную.Result
просто возвращает копиюtmp
, ничего не создавая?При втором подходе
Result.aNumerator
иResult.aDenominator
являются параметрами автоматически созданного конструктора?
F
в качестве префикса для частных полей в классе и префиксаA
для параметров метода (который вы действительно используете). В Delphi это нормально, но, видимо, в Lazarus это не компилируется. - person Jerry Dodge   schedule 08.02.2017