代码之家  ›  专栏  ›  技术社区  ›  zeus

使用虚拟类访问私有字段

  •  1
  • zeus  · 技术社区  · 6 年前

    我有以下声明:

    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;
    


    编辑/注释

    关于我为什么需要访问私有成员:我想要访问私有成员的类是 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) 等这就是为什么我只想要一个 通道 为他们所有人上课:

      {************************}
      {$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 ? 纹理 是一个由所有OpenGL delphi框架使用的非常简单的类。所以替换这个类意味着。。。我的意思是重新绘制所有openGL firemonkey框架:)这项工作相当复杂,但我同意它有可能 纯粹主义者 不想访问私人成员的人。

    我有另一个框架(视频播放器),它在每个视频帧上都给了我一个带有/高度和比例的openGL纹理ID。因此,对于每个新的帧事件,我需要更新 纹理 加上 With height 并将其发送到canvas.drawTexture(仅接受 纹理 )

    有没有办法在每一帧上进行更新 具有给定值的对象 Handle / width / 高度 scale ? 简单回答:不!是的,他们是一种方式,但我发现更多 hazardous 而不是直接访问私人成员。这种方法包括使用 ITextureAccess setwith setheight 这将最终确定纹理,然后只有在设置回手柄等。。。

    :)

    2 回复  |  直到 6 年前
        1
  •  5
  •   Yennefer    6 年前

    如果您控制着所有的类,那么这是一个糟糕的设计选择。然而,您似乎正在尝试访问一些VCL内部。如果您确定没有干净的方法获得所需的信息,那么您所做的是正确的。

    您基本上是用 相同布局 与原来的字段一样,然后在不进行类型检查的情况下进行强制转换:由于要访问的字段在两个类中的偏移量相同,因此最终将访问所需的内存。

    第二个示例之所以有效,是因为用户字段对齐正确。如果您想访问A的私有字段,最好使用填充量最小的访问器,以达到所需的偏移量,这样您需要维护的字段就更少了。您应该记录要访问哪些字段以供将来参考,以及原始类定义,以便能够发现布局随时间的变化。

    请记住,当原始类更改自己的布局时,这种肮脏的伎俩将不再像预期的那样有效。根据类的重构方式,您的代码可能只是读取了不正确的值,或者由于访问冲突而崩溃。

    起初,OP要求访问普通类中的一个私有字段。接口并没有处理这个问题,因为它们是按照@rudy所描述的方式布置的,很明显,访问这些字段会变得很困难。

        2
  •  2
  •   Rudy Velthuis    6 年前

    小心。这可能行得通,但我明白了 实现一个接口 隐藏的 指向接口VMT的实例字段,如 可打印 , 此矿井示意图中的字段:

    enter image description here

    现在如果那是隐藏的 字段被插入 之前 更多领域 图中类的一部分),很可能是您的假类的成员( 但是 没有 隐藏字段)将具有错误的偏移量,因此您的技巧可能会失败 根本不工作。

    所以你至少应该 测试

    你使用警告信息是值得赞扬的。

    更新

    TTexture . 的接口指针 ITextureAccess 插入 之后 这个 成员字段。任何补偿 那是有效的。


    纹理 公众的 手柄 , , 高度 ,以及界面 ITextureAccess 允许您设置比例,因此您可能无法 需要