delphi - Delphi 记录构造函数真的需要吗?

标签 delphi constructor records

情况

我正在学习 Nick Hodges 的“More Coding in 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

当我读 Marco Cantu 的书时,他使用了另一种方法:

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。在第二种方法中,我没有创建任何东西,因为记录有一个自动构造函数。事实上,文档是这样说的:

Records are constructed automatically, using a default no-argument constructor, but classes must be explicitly constructed. Because records have a default no-argument constructor, any user-defined record constructor must have one or more parameters.

这里我有一个用户定义的记录构造函数。所以:

  1. 是否不需要第一种方法的 tmp 上的构造函数调用?如果我想调用Reduce(这是一个过程),我需要创建一个变量。 Result 是否只是返回 tmp 的副本而不创建任何内容?

  2. 第二种方法中,Result.aNumeratorResult.aDenominator是自动创建的构造函数的参数吗?

最佳答案

记录构造函数并不是什么神奇的东西。它只是一个像其他方法一样的实例方法。你写:

tmp := TFraction.Create(...);

但是你也可以这样写:

tmp.Create(...);

我个人认为两者都不是特别有用,因为我习惯了分配和默认初始化内存的类的构造函数调用语义,然后调用构造函数方法。

特别是第二个变体让我很恼火,因为这看起来像是新手 Delphi 程序员在开始并尝试创建类的实例时所犯的典型错误。如果 TFraction 是一个类,那么该代码就不好,但就记录而言,它很好。

如果是我,我会摆脱记录构造函数,而是使用返回记录类型的新创建实例的静态类函数。我的惯例是将这些东西命名为New。但这些都是个人喜好问题。

如果你这样做,它将像这样声明:

class function New(aNumerator, aDenominator: Integer): TFraction; static;

它的实现方式如下:

class function TFraction.New(aNumerator, aDenominator: Integer): TFraction;
begin
  Result.aNumerator := ...;
  Result.aDenominator := ...;
end;

然后你可以这样调用它:

frac := TFraction.New(num, denom);

但正如我所说,这是一个偏好问题。如果您喜欢记录构造函数,请随意坚持使用它们。

<小时/>

你问是否可以跳过构造函数。就记录的分配而言,是的,您可以跳过它。至于在构造函数中运行代码,只有您可以确定。您是否希望执行该代码?

如果您希望执行该代码,但不想使用临时变量,那么您可以编写如下代码:

class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction;
begin
  Result.Create(
    fraction1.Numerator*fraction2.Denominator + fraction1.Denominator*fraction2.Numerator,
    fraction1.Denominator*fraction2.Denominator
  );
  Result.Reduce;
end;

或者,如果您更喜欢静态类函数,那么它是:

class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction;
begin
  Result := TFraction.New(
    fraction1.Numerator*fraction2.Denominator + fraction1.Denominator*fraction2.Numerator,
    fraction1.Denominator*fraction2.Denominator
  );
  Result.Reduce;
end;

关于delphi - Delphi 记录构造函数真的需要吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42119784/

相关文章:

delphi - 如何在 TThread 中正确使用 Idhttp?

delphi - 如何设置 TTabSet 组件选项卡的图像索引

delphi - TTCPServer onAccept 上的 ShowModal 导致应用程序挂起?

具有构造函数的类的 C++ vector

c++ - 未将此指针设置为 const 的构造函数会导致未检测到的问题

MySQL:限制每个用户对记录子集的访问

delphi - 如何在Delphi中一次正确地释放包含各种类型的记录?

delphi - 通过 Delphi 和 Indy 10 TIdHTTP 获取 WebDAV 内容

javascript - "add method to prototype"是什么意思

php - 从变量中减去更新字段