我有这个声明:
Type
TmyObjA = class
private
FieldA: integer;
FieldB: integer;
public
...
end;
TmyObjB = class(TmyObjA)
private
FieldC: integer;
FieldD: integer;
public
...
end;
var MyObjB = TmyObjB
我现在要访问FieldA
中的私有字段 MyObjB
。我喜欢这样:
TmyObjAPrivateAccess = class
public
FieldA: integer;
FieldB: integer;
end;
TmyObjAPrivateAccess(MyObjB).FieldA := something;
它会起作用还是我必须这样做:
TmyObjBPrivateAccess = class
public
FieldA: integer;
FieldB: integer;
FieldC: integer;
FieldD: integer;
end;
TmyObjBPrivateAccess(MyObjB).FieldA := something;
NB:我测试过,它在两种变体中都可以工作,但这不是演示,它似乎可以工作
编辑/注释
关于为什么我需要访问私有成员的原因:我想访问私有成员的类是TTexture
:
TTexture = class(TInterfacedPersistent, ITextureAccess)
private
FWidth: Integer;
FHeight: Integer;
FPixelFormat: TPixelFormat;
FHandle: TTextureHandle;
FStyle: TTextureStyles;
FMagFilter: TTextureFilter;
FMinFilter: TTextureFilter;
FTextureScale: Single;
FRequireInitializeAfterLost: Boolean;
FBits: Pointer;
FContextLostId: Integer;
FContextResetId: Integer;
protected
public
property BytesPerPixel: Integer read GetBytesPerPixel;
property MinFilter: TTextureFilter read FMinFilter write SetMinFilter;
property MagFilter: TTextureFilter read FMagFilter write SetMagFilter;
property PixelFormat: TPixelFormat read FPixelFormat write SetPixelFormat;
property TextureScale: Single read FTextureScale; // hi resolution mode
property Style: TTextureStyles read FStyle write SetStyle;
property Width: Integer read FWidth write SetWidth;
property Height: Integer read FHeight write SetHeight;
property Handle: TTextureHandle read FHandle;
end;
这是我的TmyObjA
。
然后将此类更新为
TALPlanarTexture = class(TTexture)
private
FSecondTexture: TTexture;
FThirdTexture: TTexture;
FFormat: TALTextureFormat;
protected
....
end;
这是我的TmyObjB
。但是我还有其他几个像这样的类,例如TALBiPlanarTexture = class(TALTexture)
等。这就是为什么我只希望对所有人使用一个 access 类的原因:< / p>
{************************}
{$IF CompilerVersion > 32} // tokyo
{$MESSAGE WARN 'Check if FMX.Types3D.TTexture still has the exact same fields and adjust the IFDEF'}
{$ENDIF}
TALTextureAccessPrivate = class(TInterfacedPersistent)
public
FWidth: Integer;
FHeight: Integer;
FPixelFormat: TPixelFormat;
FHandle: TTextureHandle;
FStyle: TTextureStyles;
FMagFilter: TTextureFilter;
FMinFilter: TTextureFilter;
FTextureScale: Single;
FRequireInitializeAfterLost: Boolean;
FBits: Pointer;
FContextLostId: Integer;
FContextResetId: Integer;
protected
public
end;
现在为什么我需要访问TTExture
的私有成员? TTexture
是所有OpenGL delphi框架都使用的非常简单的类。因此,替换此类的意思是……很好的意思是重新绘制了所有的openGL firemonkey框架:)相当复杂的工作,但我同意对于不想使用私有成员的<纯粹>精通人的可能性。
我有另一个框架(视频播放器),在每个视频框架上都给了我一个带有/高度和比例的openGL纹理ID。因此,在每个新的框架事件上,我都需要更新其TTexture
的Handle及其With
/ height
并将其发送到canvas.drawTexture(仅接受{{1 }})
是否可以通过给定的TTexture
/ TTexture
/ Handle
和width
在每个帧上更新height
对象?简单回答:不!是的,他们的方式是一种方法,但我发现scale
比直接访问私有成员要多得多。这种方式包括使用hazardous
将句柄重置为零,然后调用ITextureAccess
和setwith
将最终确定纹理,然后再设置回切句柄,等等...
但是无论如何,我的问题不是关于访问私人成员是好是坏:)
答案 0 :(得分:5)
如果您控制所有类,那么这是一个错误的设计选择。但是,您似乎正在尝试访问某些VCL内部组件。如果您确定没有干净的方法来获取所需的信息,那么您所做的是正确的。
您基本上是在定义一个与相同布局作为原始类的新类,然后在不进行类型检查的情况下进行转换:由于您要访问的字段位于以下事实在两个类中具有相同的偏移量,您最终将访问所需的内存。
您的第二个示例有效,因为用户字段正确对齐。如果要访问A的私有字段,最好使用最小填充量的访问器来达到所需的偏移量,这样就可以减少要维护的字段。您应该记录要访问哪些字段以供将来参考,以及原始的类定义,以便可以发现布局随时间的变化。
请记住,当原始类更改其自己的布局时,此肮脏的把戏将不再起作用。根据类的重构方式,您的代码可能只是读取了错误的值,或者因访问冲突而崩溃。
更新 首先,OP要求访问一个普通班级的私有字段。接口未按此答案处理,因为它们按@rudy所述进行了布局,并且显然很难访问这些字段。
答案 1 :(得分:2)
注意。这可能有效,但是我看到TTexture 实现了一个接口。这意味着它将具有指向接口VMT的隐藏实例字段,例如 IPrintable , IEDitable 和 IComparable 我的这张图中的字段:
现在,如果在私有成员之前(之前)插入了隐藏的 ITextureAccess 字段(在图中该类的 more字段部分之前),假类的成员(更多字段,但没有隐藏字段)很可能具有错误的偏移量,因此您的把戏可能不完全可以。
因此对于这种情况,您至少应测试。如果您这样做了,并且得到了预期的结果,那么您就有一个有效的破解方法。
您对警告消息的使用值得称赞。
我检查了TTexture
的偏移量。 ITextureAccess 的接口指针在 FContextResetId 成员字段的之后插入。 之前的所有有效偏移量。
但是 TTexture 具有要设置的属性的 public 属性: Handle , Width ,< em> Height ,并且界面 ITextureAccess 允许您设置比例,因此您可能不需要。
答案 2 :(得分:0)
只需调用 FieldAddress 即可访问内存中的字段:
var
LHeight: PInteger;
begin
LHeight := Self.FieldAddress('FHeight');
Assert(LHeight <> nil);
LHeight^ := 100;
注意:你也可以在其他对象中使用这个,这个方法是公开的