Delphi:在后代类中写入私有祖先的字段

And*_*rew 10 delphi oop private private-members

我需要修复第三方组件.该组件的类具有私有变量,其后代主动使用它:

TThirdPartyComponentBase = class
private
  FSomeVar: Integer;
public
  ...
end;

TThirdPartyComponent = class (TThirdPartyComponentBase)
protected
   procedure Foo; virtual;
end;

procedure TThirdPartyComponent.Foo;
begin
  FSomeVar := 1; // ACCESSING PRIVATE FIELD!
end; 
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为两个类都在同一个单元中,因此它们有点像"朋友".

但是,如果我尝试在新单元中创建一个新类

TMyFixedComponent = class (TThirdPartyComponent)
  procedure Foo; override; 
end;
Run Code Online (Sandbox Code Playgroud)

我不能再访问FSomeVar,但我需要将它用于我的修复.我真的不想在我的代码中重现所有基类树.

如果可能的话,你能否建议一些快速破解访问该私有字段而不更改原始组件的单元

LU *_* RD 18

通过使用class helpers它可以从派生类中完成对基类的私有部分的访问,而不会失去类型安全性.

只需在另一个单元中添加这些声明:

Uses YourThirdPartyComponent;

type
  // A helper to the base class to expose FSomeVar
  TMyBaseHelper = class helper for TThirdPartyComponentBase
  private
    procedure SetSomeVar( value : integer);
    function GetSomeVar: integer;
  public
    property SomeVar:integer read GetSomeVar write SetSomeVar;
  end;

  TMyFixedComponent = class helper for TThirdPartyComponent
  protected
    procedure Foo;
  end;

procedure TMyFixedComponent.Foo;
begin
  // Cast to base class and by the class helper TMyBaseHelper the access is resolved
  TThirdPartyComponentBase(Self).SomeVar := 1; 
end;

function TMyBaseHelper.GetSomeVar: integer;
begin
  Result := Self.FSomeVar; // ACCESSING PRIVATE FIELD!
end;

procedure TMyBaseHelper.SetSomeVar(value: integer);
begin
  Self.FSomeVar := value; // ACCESSING PRIVATE FIELD!
end;

// Testing
var
  TSV: TThirdPartyComponent;
begin
  TSV := TThirdPartyComponent.Create;
  try
    TSV.Foo;    
    WriteLn(IntToStr(TSV.SomeVar));  // Writes 1
  finally
    TSV.Free;
  end;
end.
Run Code Online (Sandbox Code Playgroud)

从代码中的注释可以看出,FSomeVar是由类中的类助手公开的TThirdPartyComponentBase.另一个用于TThirdPartyComponent实现Foo过程的类助手.在那里,通过对SomeVar基类的类型转换来访问基类助手的属性.

  • 请注意,另一个单元中的类助手不能再像Delphi 10.1 Berlin那样访问私有成员,因为这被Embarcadero视为一个错误.有关详细信息,请参阅http://stackoverflow.com/questions/9410485/how-do-i-use-class-helpers-to-access-strict-private-members-of-a-class#comment61026976_9410717 (3认同)

ood*_*ner 5

您必须使用hack来访问不同单元中任何类(包括基类)中的私有字段.在您的情况下,在您的单位中定义:

type
  __TThirdPartyComponentBase = class 
  private 
    FSomeVar: Integer;
  end;
Run Code Online (Sandbox Code Playgroud)

然后获取访问权限:

__TThirdPartyComponentBase(Self).FSomeVar := 123;
Run Code Online (Sandbox Code Playgroud)

当然,这很危险,因为您需要控制基类中的更改.因为如果字段布局将被更改而您将错过这一事实,那么上述方法将导致失败,AV等.

  • @Andrew:请注意,一旦祖先(第三方)组件的内存布局发生变化,此解决方案就会中断.您可能不会注意到它会中断,因为没有什么能够警告您.或者你可能会看到虚假的错误行为(如果你很幸运:访问违规),因为你开始覆盖不属于你的数据. (2认同)