当前位置 : 主页 > 编程语言 > delphi >

如何在Delphi中覆盖继承的类属性?

来源:互联网 收集:自由互联 发布时间:2021-06-23
在一个文件中,我有一个带有ID属性的基类: type TBase = class private class function GetID(ACombo: TCombo): Integer; virtual; class procedure SetID(ACombo: TCombo; AValue: Integer); virtual; public class property ID[ACombo: T
在一个文件中,我有一个带有ID属性的基类:

type
  TBase = class
  private  
    class function GetID(ACombo: TCombo): Integer; virtual;
    class procedure SetID(ACombo: TCombo; AValue: Integer); virtual;
  public  
    class property ID[ACombo: TCombo]: Integer read GetID write SetID;  
  end;

在第二个文件中,我有另一个类,从TBase下降.无意中,或无知或任何时候,都会创建一个与现有属性/字段同名的新属性/字段.

type
  TSubBase = class(TBase)
  private  
    class function GetID(ACombo: TCombo): Integer; override;
    class procedure SetID(ACombo: TCombo; AValue: Integer); override;
  end;

并以下一种方式使用这些类:

TBaseClass = class of TBase;

  function Base(): TBaseClass;

implementation

var
  BaseInstance: TBaseClass;

function Base(): TBaseClass;
begin
  if not Assigned(BaseInstance) then
  begin
     if SOME_PARAM then
      BaseInstance:= TBase
    else
      BaseInstance:= TSubBase;
  end;
  Result := BaseInstance;
end;
if Base.StationCode[cmbStation] = SOME_VALUE then

但是我在编译时遇到了错误:

[DCC Error] uMyFile.pas(69): E2355 Class property accessor must be a class field or class static method

我一直在尝试使用静态关键字……并根据以下同事的建议找到了一些解决方法.

type
  TBase = class
  private  
    class function GetIDStatic(ACombo: TCombo): Integer; static;
    class procedure SetIDStatic(ACombo: TCombo; AValue: Integer); static;    
    class function GetID(ACombo: TCombo): Integer; virtual; abstract;
    class procedure SetID(ACombo: TCombo; AValue: Integer); virtual; abstract;
  public  
    class property ID[ACombo: TCombo]: Integer read GetIDStatic write SetIDStatic;  
  end;

  TSubBase = class(TBase)
  private  
    class function GetID(ACombo: TCombo): Integer; override;
    class procedure SetID(ACombo: TCombo; AValue: Integer); override;
  end;

  TBaseClass = class of TBase;

  function Base(): TBaseClass;

implementation

var
  BaseInstance: TBaseClass;

function Base(): TBaseClass;
begin
  if not Assigned(BaseInstance) then
  begin
     if SOME_PARAM then
      BaseInstance:= TBase
    else
      BaseInstance:= TSubBase;
  end;
  Result := BaseInstance;
end;

class function TBase.GetIDStatic(ACombo: TCombo): Integer; static;
begin
  Result := BaseInstance.GetID(ACombo);
  // Or maybe below ?
  // Result := Base().GetID(ACombo); 
end;

class procedure TBase.SetIDStatic(ACombo: TCombo; AValue: Integer); static;
begin
  BaseInstance.SetID(ACombo, AValue);
  // Or maybe below ?
  // Base().SetID(ACombo, AValue); 
end;

但是在最后一个变体中 – 实现是丑陋的,我同意大卫关于使用类属性和SIMPLY重构的方法留下“梦想”,如下所述:

class properties ID[ACombo: TCombo]: Integer ....
  =>> 
  class function GetID(ACombo: TCombo): Integer; virtual;
  class pocedure SetID(ACombo: TCombo; AValue: Integer); virtual;

谢谢大家在那里挖掘乐趣!

错误本身告诉:“类属性访问器必须是……类静态方法”

你告诉过你可以编译TBase但是当你添加TSubBase时会弹出错误.
但不应允许TBase编译.如果是 – 那么Delphi中就有一个错误.

http://docwiki.embarcadero.com/RADStudio/XE5/en/Methods#Class_Methods

In the defining declaration of a class method, the identifier Self
represents the class where the method is called (which can be a
descendant of the class in which it is defined.) If the method is
called in the class C, then Self is of the type class of C. Thus you
cannot use Self to access instance fields, instance properties, and
normal (object) methods. You can use Self to call constructors and
other class methods, or to access class properties and class fields.

所以我们可以想到一些解决方法,明确说明我们想要调用方法的类.像这样的东西:

class function GetIDStatic(ACombo: TCombo): Integer; static;
var RealClass: TBaseClass;
begin
  RealClass := Self; /// will not compile !!!
  Result := RealClass.GetID(ACombo);
end;

但…

Unlike ordinary class methods, class static methods have no Self parameter at all

因此,静态方法无法知道在调用站点调用了哪个类.因此,它们恰好称为函数体,在自己的类中定义.在这个地方 – 这将是一个抽象的功能.

然而,有一个明显的解决方法,可以写出类似的东西

if Base().n.StationCode[cmbStation] = SOME_VALUE then

但是实施几乎没有效率,所以几乎不值得.

网友评论