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

发布于 2024-09-29 18:08:01 字数 638 浏览 7 评论 0原文

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

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; 

这是有效的,因为两个类位于同一单元中,因此它们有点“朋友”。

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

TMyFixedComponent = class (TThirdPartyComponent)
  procedure Foo; override; 
end;

我将无法再访问 FSomeVar,但我需要使用它来进行修复。我真的不想在我的代码中重现所有基类树。

如果可能的话,您能否建议一些快速的技巧来访问该私有字段而不更改原始组件的单位

I need to fix a third-party component. This component's class has private variable which is actively used by its descendants:

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; 

This works because both classes are in the same unit, so they're kinda "friends".

But if I'll try to create a new class in a new unit

TMyFixedComponent = class (TThirdPartyComponent)
  procedure Foo; override; 
end;

I can't access FSomeVar anymore, but I need to use it for my fix. And I really don't want to reproduce in my code all that tree of base classes.

Can you advise some quick hack to access that private field without changing the original component's unit if it's possible at all?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

遇见了你 2024-10-06 18:08:01

通过使用类帮助器,可以实现从派生类访问基类的私有部分,而不会失去类型安全性。

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

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.

从代码中的注释可以看出,FSomeVarTThirdPartyComponentBase 类中的类帮助程序公开。
TThirdPartyComponent 的另一个类帮助器实现了 Foo 过程。在那里,对基类助手的 SomeVar 属性的访问是通过类型转换到基类来实现的。

By the use of class helpers it's possible to accomplish access to the private parts of the base class from the derived class without loosing type safety.

Just add these declarations in another unit:

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.

As can be seen from comments in code, FSomeVar is exposed by a class helper from the TThirdPartyComponentBase class.
Another class helper for the TThirdPartyComponent implements the Foo procedure. In there, access to the SomeVar property of the base class helper is made via a type cast to the base class.

囍笑 2024-10-06 18:08:01

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

type
  __TThirdPartyComponentBase = class 
  private 
    FSomeVar: Integer;
  end;

然后获取访问权限:

__TThirdPartyComponentBase(Self).FSomeVar := 123;

当然,这是危险的,因为您需要控制基类中的更改。因为如果字段布局发生变化而您会错过这个事实,那么上述方法将导致失败、AV 等。

You have to use a hack to access a private field in any class (including a base class) in a different unit. In your case define in your unit:

type
  __TThirdPartyComponentBase = class 
  private 
    FSomeVar: Integer;
  end;

Then get the access:

__TThirdPartyComponentBase(Self).FSomeVar := 123;

Of course, that is dangerous, because you will need to control changes in the base class. Because if the fields layout will be changed and you will miss this fact, then the above approach will lead to failures, AV's, etc.

隔岸观火 2024-10-06 18:08:01

不知道这是否有帮助,但我似乎记得有一种方法可以将私有变量“破解”为可见性。

例如,我知道,当我将属性从较低的可见性(在基类中)移动到更可见的级别(在我的后代中)时,我遇到了来自编译器的警告。该警告指出,它正在以不同的可见性级别进行声明...

已经有一段时间了,我不确定,但我相信您可以做的是在您的后代中将相同的变量声明为受保护的。 (您可能必须使用 Redeclare 关键字才能进行编译。)

抱歉,我没有关于如何执行此操作的更多具体信息(如果确实可能的话)。也许这篇文章会提示这里的向导之一纠正我! :-)

Don't know if this will help, but I seem to recall there is a way to "crack" a private variable into visibility.

I know, for example, I've encountered warnings from the compiler when I've moved a property from lower visibility (in the base class) to a more visible level (in my descendant). The warning stated that it's being declared at a different level of visibility...

It's been some time and I'm not certain, but I believe what you can do is in your descendant declare the same variable as protected. (You may have to use the Redeclare keyword for this to compile.)

Sorry I don't have more specific information on how to do this (if it's indeed possible.) Perhaps this posting will prompt one of the wizards here into correcting me! :-)

生来就爱笑 2024-10-06 18:08:01

通过 TThirdPartyComponent 中的受保护属性公开私有变量的值。

TThirdPartyComponent = class (TThirdPartyComponentBase)
private
   Procedure SetValue(Value: Integer);
   Function GetValue: Integer;
protected
   Property MyVar: Integer read GetValue write Setvalue; 
   procedure Foo; virtual;
end;

Procedure TThirdPartyComponent.SetValue(Value: Integer);
begin
  FSomeVar := Value ;
end;

Function GetValue: Integer;
begin
  result := FSomeVar;
end;

TMyFixedComponent 类中,在您想要覆盖的过程中使用 MyVar 属性。

Expose the value of the private variable by a protected property in TThirdPartyComponent.

TThirdPartyComponent = class (TThirdPartyComponentBase)
private
   Procedure SetValue(Value: Integer);
   Function GetValue: Integer;
protected
   Property MyVar: Integer read GetValue write Setvalue; 
   procedure Foo; virtual;
end;

Procedure TThirdPartyComponent.SetValue(Value: Integer);
begin
  FSomeVar := Value ;
end;

Function GetValue: Integer;
begin
  result := FSomeVar;
end;

In TMyFixedComponent class use the MyVar Property in the procedure which you would like to override.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文