СИТУАЦИЯ
Я изучаю "Больше кодирования в 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;
ПРОБЛЕМА
Так как оператор перегружает return a 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
. Во втором подходе я вместо этого ничего не создаю, потому что записи имеют автоматический конструктор. Фактически, документация гласит, что:
Записи создаются автоматически, используя аргумент no-argument по умолчанию конструктор, но классы должны быть явно построены. Потому как записи имеют конструктор без аргументов по умолчанию, любые пользовательские конструктор записи должен иметь один или несколько параметров.
Здесь у меня есть пользовательский конструктор записи. Итак:
-
Является ли вызов конструктора на
tmp
первого подхода не нужен? Если я хочу вызватьReduce
(это процедура), мне нужно создать переменную. Является лиResult
просто возвращением копииtmp
без создания чего-либо? -
Во втором подходе есть
Result.aNumerator
иResult.aDenominator
параметры автоматического созданного конструктора?