Delphi - 继承/覆盖常量数组?

Jos*_*ons 2 delphi inheritance

首先,对这篇文章的篇幅表示道歉.如果简洁是智慧的灵魂,那么这是一个无知的问题.

我想我的问题归结为:

在Delphi子类中覆盖常量数组的最佳方法是什么?

背景:

= - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = -

我有一个在父类中定义的常量数组,也在很多子类中定义.数组元素的类型总是相同的,但是元素的数量和确切的数据从一个子节点到另一个子节点不同(我正在描述数据库表,因为在编译时需要元数据的特定网格控件,但那不是重点).

我有几个函数作用于这些数组.作为一个简单的例子,我可能有一个函数来返回数组的最后一个元素.

如果在父级中定义"GetLastElement",然后从子级调用该继承函数,它仍将作用于父级版本的数组.这不是我的预期.看起来孩子们应该在他们自己的本地版本的数组上调用继承的函数.

目前,我必须在每个子类中复制这些函数,这令人抓狂.

我希望能够在我的常量数组的本地版本上使用继承函数.最好的方法是什么?我已经考虑过在基类中定义一个返回静态数组的函数,然后为每个子项覆盖它.如果我这样做,那么我就不会在数组上进行操作,我会根据函数结果进行操作.

这将解决继承问题,但它引入了一个新问题,我必须定义一个新类型来封装数组,并修改我的(已经复杂的)网格控件以使用该类型.

欢迎任何建议.

下面是一个简化的应用程序,演示了我在说什么:

在主要形式:

implementation

{$R *.dfm}

uses
  ParentClass, Descendant1, Descendant2;

procedure TfrmMain.btnTestClick(Sender: TObject);
var
  d1, d2: TParentClass;
begin
  d1 := TDescendant1.Create;
  d2 := TDescendant2.Create;

  //as it stands, this will return "E", then "A", which is good.
  //but if you move the LastElementOfArray function to the ParentClass,
  //then it will return "E", "E", ignoring the version of the array
  //defined inside TDescendant2.
  ShowMessage('d1=' + d1.LastElementOfArray);
  ShowMessage('d2=' + d2.LastElementOfArray);
end;


end.
Run Code Online (Sandbox Code Playgroud)

在名为ParentClass.pas的文件中:

unit ParentClass;

interface

type
  TParentClass = class
  public
    function LastElementOfArray: string; virtual; abstract;
  end;

const
  c_MyConstantArray: array[1..5] of string = ('A','B','C','D','E');

implementation

end.
Run Code Online (Sandbox Code Playgroud)

在一个名为Descendant1.pas的单位

//here, we will just take whatever array we got from the parent
unit Descendant1;

interface

uses
  ParentClass;

type
  TDescendant1 = class(TParentClass)
  public
    function LastElementOfArray: string; override;
  end;

implementation

{ TDescendant1 }

function TDescendant1.LastElementOfArray: string;
begin
  Result := c_MyConstantArray[High(c_MyConstantArray)];
end;

end.
Run Code Online (Sandbox Code Playgroud)

在名为Descendant2.pas的文件中

//override with a new version of the constant array (same length)
unit Descendant2;

interface

uses
  ParentClass;

type
  TDescendant2 = class(TParentClass)
  public
    function LastElementOfArray: string; override;
  end;

const
  c_MyConstantArray: array[1..5] of string = ('E','D','C','B','A');

implementation

{ TDescendant2 }

function TDescendant2.LastElementOfArray: string;
begin
  //I hate defining this locally, but if I move it to ParentClass,
  //then it will act on the ParentClass version of the array, which
  //is **NOT** what I want
  Result := c_MyConstantArray[High(c_MyConstantArray)];
end;

end.
Run Code Online (Sandbox Code Playgroud)

Bar*_*lly 9

您可以考虑使用动态数组.动态数组可以在这样的表达式中初始化:

type
  TStringArray = array of string;
// ...
var
  x: TStringArray;
begin
  x := TStringArray.Create('A', 'B', 'C')
end;
Run Code Online (Sandbox Code Playgroud)

使用这种方法,您可以将数组定义放在例如虚拟类属性getter中,或者通过类属性getter访问的lazily-initialized(通过虚拟调用)类变量.然后,需要使用"this"类的数组定义的方法可以简单地通过属性使用虚拟getter.

使用命名的动态数组也远离了必须为不同长度的数组使用单独类型的问题,而不会失去在表达式中初始化的能力.