【问题标题】:Delphi subclass constructor overrideDelphi 子类构造函数覆盖
【发布时间】:2017-04-18 19:46:08
【问题描述】:

我在一个文件中声明了以下类:

type
 TCongruence = class(TObject)
  private
   a, b, n, numClass: integer;
   solutions, vals: TSolutions;
   hasSolutions: boolean;
   function divides(a, b: integer): boolean;
   function modulo(a, b: integer): integer;
  public
   constructor Create(a, b, n: integer); virtual;
   function getSolutions: TSolutions; virtual;
   function gcdExtended(p, q: integer): TSolutions;
   class function getGCD(u, v: integer): integer;
   property valA: integer read a;
   property valB: integer read b;
   property valN: integer read n;
   property getClass: integer read numClass;
   property hasSol: boolean read hasSolutions;
 end;

type
 TConguenceSystem = class(TCongruence)
  private
   system: array of TCongruence;
  public
   constructor Create(a: array of TCongruence); override;
   function getSolutions: integer; override;
 end;

如您所见,第二个是子类,因为我需要使用TCongruence 类中实现的所有功能。我已将构造函数声明为 virtual,以便我可以在后代上调用覆盖。

正确吗?我是否必须删除虚拟/覆盖并简单地使用这样的构造函数? (下)

constructor Create(a: array of TCongruence); 

我想在这种情况下我隐藏了父亲的构造函数。我已经声明了这个构造函数:

constructor TConguenceSystem.Create(a: array of TCongruence);
var i: integer;
begin

 SetLength(system, length(a)); // private var system: array of TCongruence
 for i := Low(a) to High(a) do
  begin
   system[i] := a[i];
  end;

 solutions := false;

end;

【问题讨论】:

  • 对我来说看起来不正确的层次结构。 getSolutions也改了签名
  • 我认为这是正确的,我使用相同的 shema。

标签: delphi


【解决方案1】:

当您打算在后代类中重写具有相同签名的方法的行为时,您必须在基类中声明virtual,然后后代类将使用override

但是,如果您希望引入具有不同签名的新方法,那么您必须使用overload 指令如果您在同一个类中声明该方法。这只是允许对具有不同签名的完全不同的方法重复使用相同的方法名称。例如:

 TCongruence = class(TObject)
   public
     constructor Create(a : integer); overload;
     constructor Create(a, b, n: integer); overload;
 end;

但是,如果您要在后代类中声明具有不同签名的新方法,则不需要这些修饰。

 TCongruence = class(TObject)
   public
     constructor Create(a, b, n: integer);
 end;

 TCongruenceSystem = class(TCongruence)
   public
     constructor Create(a: array of TCongruence);
 end;

以上内容很好——你没有覆盖原来的构造函数,你只是引入了一个带有新签名的新构造函数。由于后者属于具有不同名称的新类,因此没有歧义并且不需要overload。您甚至可以在此处以通常的方式访问祖先方法:

 TCongruence = class(TObject)
   private
     Fa, Fb, Fn : integer;
   public
     constructor Create(a, b, n: integer);
 end;

 TCongruenceSystem = class(TCongruence)
   private
     FArr : array of TCongruence;
   public
     constructor Create(a: array of TCongruence);
 end;

constructor TCongruence.Create(a, b, n: integer);
begin
  inherited Create;
  Fa := a;
  Fb := b;
  Fn := n;
end;

constructor TCongruenceSystem.Create(a: array of TCongruence);
var
  c : TCongruence;
  i : integer;
begin
  inherited Create(a[0].Fa, a[1].Fb, a[2].Fn);
  SetLength(FArr, Length(a));
  i := 0;
  for c in a do begin
    FArr[i] := c;
    Inc(i);
  end;
end;

但是,如果没有 overload 指令,则不允许执行以下操作:

var
  cs : TCongruenceSystem;
begin
  cs := TCongruenceSystem.Create(1, 2, 3); 
end.

因为TCongruenceSystem 隐藏了基类Create,它接受三个integer 参数。但是,如果您允许overload

 TCongruence = class(TObject)
   private
     Fa, Fb, Fn : integer;
   public
     constructor Create(a, b, n: integer); overload;
 end;

 TCongruenceSystem = class(TCongruence)
   private
     FArr : array of TCongruence;
   public
     constructor Create(a: array of TCongruence); overload;
 end;

那么上面的cs := TCongruenceSystem.Create(1, 2, 3);调用就被允许了,祖先构造函数将被用来构建后代类。

这些方法可以组合使用,例如:

 TCongruence = class(TObject)
   public
     constructor Create(a : integer); overload; virtual; {overridable}
     constructor Create(a, b, n: integer); overload;     {only in base}
 end;

 TCongruenceSystem = class(TCongruence)
   public
     constructor Create(a:integer); overload; override;  {overrides parent}
     constructor Create(a: string); overload;            {introduce new}
 end;

在构造函数的情况下,您正在引入具有不同参数集的方法,因此这是允许的。但是,在getSolutions 的情况下,该函数不带参数,仅在返回类型上有所不同。然而,重载的方法需要有不同的参数集,因此在后代类中不允许这种类型的突变。如果您希望后代类中的 getSolutions 也是具有不同返回类型的无参数函数,则需要采用不同的名称。

【讨论】:

  • 我明白了,谢谢。查看我编辑的问题,我已经编写了 TCongruenceSystem 的实现。需要在子类中调用继承的Create吗?
  • @RaffaeleRossi 你不需要调用它——这取决于你想要什么行为。
猜你喜欢
  • 2021-01-17
  • 2015-02-01
  • 1970-01-01
  • 2017-02-03
  • 1970-01-01
  • 2017-01-21
  • 2014-06-09
  • 1970-01-01
  • 2011-05-01
相关资源
最近更新 更多