Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use class helpers to access strict private members of a class?

This is a follow-up question to: How to hide a protected procedure of an object?
(I'm a bit fuzzy on the whole class helper concept)

Suppose I have an class like:

type  TShy = class(TObject)  strict private   procedure TopSecret; private   procedure DirtyLaundry;   protected    procedure ResistantToChange; end;  

I know I can access the private method if I have the source code by adding a descendent class in the same unit.

I have 2 questions:
- How do I employ a class helper to access the strict private member?
- Can I use a class helper in a separate unit to access (strict) private members?

like image 573
Johan Avatar asked Feb 23 '12 09:02

Johan


2 Answers

Up to, and including Delphi 10.0 Seattle, you can use a class helper to access strict protected and strict private members, like this:

unit Shy;  interface  type   TShy = class(TObject)   strict private     procedure TopSecret;   private     procedure DirtyLaundry;   protected     procedure ResistantToChange;   end; 

unit NotShy;  interface  uses   Shy;  type   TNotShy = class helper for TShy   public     procedure LetMeIn;   end;  implementation  procedure TNotShy.LetMeIn; begin   Self.TopSecret;   Self.DirtyLaundry;   Self.ResistantToChange; end;  end. 

uses   ..., Shy, NotShy;  procedure TestShy; var   Shy: TShy; begin   Shy := TShy.Create;   Shy.LetMeIn;   Shy.Free; end; 

However, starting with Delphi 10.1 Berlin, this no longer works! Class helpers can no longer access strict protected, strict private or private members. This "feature" was actually a compiler bug that Embarcadero has now fixed in Berlin. You are out of luck.

like image 67
Remy Lebeau Avatar answered Sep 22 '22 02:09

Remy Lebeau


Access to private and strict private members of a class with class helpers was removed in Delphi 10.1 Berlin. See Closing the Class Helpers Private Access Loophole.

But there is still an open loophole:

unit Shy;  interface  type   TShy = class(TObject)   strict private     procedure TopSecret;   private     procedure DirtyLaundry;   protected     procedure ResistantToChange;   end;  implementation  procedure TShy.DirtyLaundry; begin   WriteLn('DirtyLaundry'); end;  procedure TShy.ResistantToChange; begin   WriteLn('ResistantToChange'); end;  procedure TShy.TopSecret; begin   WriteLn('TopSecret'); end;  end. 

Program TestClassHelpers;  {$APPTYPE CONSOLE}  Uses   Shy;  type   TNotShy = class helper for TShy   public     procedure LetMeIn;   end;  procedure TNotShy.LetMeIn; var   P : procedure of object; begin   TMethod(P).Code := @TShy.TopSecret;   TMethod(P).Data := Self;   P; // Call TopSecret   TMethod(P).Code := @TShy.DirtyLaundry;   TMethod(P).Data := Self;   P; // Call DirtyLaundry;   Self.ResistantToChange;  // Protected access works without problems end;  var   myObj: TShy; begin   myObj := TShy.Create;   try     myObj.LetMeIn;     ReadLn;   finally     myObj.Free;   end; end. 
like image 35
LU RD Avatar answered Sep 21 '22 02:09

LU RD