【问题标题】:Delphi - Inherit / Override a constant array?Delphi - 继承/覆盖常量数组?
【发布时间】:2009-07-21 13:24:23
【问题描述】:

首先,对这篇文章的长度表示歉意。如果简洁是智慧的灵魂,那么这是一个愚蠢的问题。

我认为我的问题归结为:

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

背景:

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

我有一个在父类和许多子类中定义的常量数组。 数组元素的类型始终相同,但元素的数量和确切数据因一个子元素而异(我正在描述数据库表,因为特定的网格控件在编译时需要元数据,但这不是重点)。

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

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

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

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

这将解决继承问题,但它在 I'd have to define a new type to encapsulate the array 中引入了一个新问题,并修改了我的(已经很复杂的)网格控件以使用该类型。

欢迎提出任何建议。

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

主要形式:

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.

在名为 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.

在一个名为 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.

在名为 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.

【问题讨论】:

  • 您的常量C_MyConstantArray 肯定是在类定义之外定义的,因此是全局(单位范围)常量。大概是 ParentClass 版本正在被使用,因为它首先出现在主窗体的 uses 子句中,尽管这不是我直观地期望的。

标签: delphi inheritance


【解决方案1】:

您可以考虑改用动态数组。动态数组可以用这样的表达式初始化:

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

使用这种方法,您可以将数组定义放入例如一个虚拟类属性 getter,或一个通过类属性 getter 访问的延迟初始化(通过虚拟调用)类变量。然后,需要使用“this”类的数组定义的方法可以简单地通过属性使用虚拟getter。

使用命名的动态数组还避免了必须为不同长度的数组使用不同类型的问题,而不会失去在表达式中初始化的能力。

【讨论】:

  • 现在那个非常有用的!如果我在一年前就知道这一点就好了 ;-) 你是否知道 Delphi 编译器从哪个版本开始支持这种语法?非常感谢您的精彩回答!
【解决方案2】:

处理此问题的最简单方法是拥有数组的受保护属性(如 Barry 建议的动态),并在构造函数中分配此属性(如有必要)。然后您的父母可以针对这个内部数组实现,您的孩子都将继承该功能。

您通过直接引用常量的方法的问题是范围之一。每次进行引用时,它都会与它所看到的相反,首先是本地实现部分(从调用向上),然后是接口,然后是实现中的单元,然后是接口中的单元.通过使用引用,在范围内或不在范围内不再重要...您的对象始终可以使用引用来处理它当前设计的操作对象。

【讨论】:

    猜你喜欢
    • 2019-06-29
    • 2011-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    相关资源
    最近更新 更多