如何在C++ Builder中实现Delphi的protected成员访问技巧?

3
我需要访问受保护的TControlItem.InternalSetLocation方法。在Delphi中,您可以这样做:
type
  THackControlItem = class(TControlItem);

在C++ Builder中如何实现这个?

2
即使在 Delphi 中,这仅适用于受保护的成员,而不是私有成员。顺便说一下。 - MartynA
1
我所知道的,访问私有成员唯一的方式是通过RTTI。你提到的那种方法被称为“受保护的Hack”;它只适用于受保护的成员。 - HeartWare
1
@HeartWare:RTTI仅在启用私有成员的情况下才有效。即使在类助手错误被更多或更少地关闭后,仍然存在辅助黑客。当然,这些在C++中不起作用。因此,我会在Delphi中执行此操作,公开值以便C++可以访问它们。我在博客中写了关于此事:http://rvelthuis.blogspot.com/2018/01/accessing-private-methods-of-another.html - Rudy Velthuis
或者你可以使用友元类:http://docwiki.embarcadero.com/RADStudio/Tokyo/zh-cn/Friends_Of_Classes - Vancalar
1
Spektre和Rudy:当然没有人会更改vcl源代码来做到这一点,THackControlItem本来就是TControlItem的后代,我只是想澄清一般情况下友元类并不起作用,“但只有在派生类中才有效”,干杯。 - Vancalar
显示剩余7条评论
2个回答

2

与Delphi类似,您需要继承该类并覆盖和公开受保护的函数。然而,我不建议在生产代码中使用它。

class THackControlItem : public TControlItem
{
public:
    void __fastcall InternalSetLocation(int AColumn, int ARow, bool APushed, bool MoveExisting)
    {
        TControlItem::InternalSetLocation(AColumn, ARow, APushed, MoveExisting);
    }
};

在程序中
TControlItem* ci = ...;
static_cast<THackControlItem*>(ci)->InternalSetLocation(...);

1

我认为Remy Lebeau向我展示了一个很好的技巧,但是找不到相关的问答了...

//---------------------------------------------------------------------------
#ifndef _TDirectMemoryStream
#define _TDirectMemoryStream
class TDirectMemoryStream:TMemoryStream // just for accessing protected SetPointer
    {
public:
    void SetMemory(BYTE *ptr,DWORD siz) { SetPointer(ptr,siz); Position=0; };
    };
#endif
//---------------------------------------------------------------------------

你只需创建一个继承所需访问的类的子类。现在只需为受保护成员添加get/set函数即可...
现在使用:
TMemoryStream *mem=new TMemoryStream(); // original class instance you want to access

// overtype to our new class and access/use you get/set ...
((TDirectMemoryStream*)(mem))->SetMemory(hdr->lpData,hdr->dwBytesUsed);

delete mem; // release if not needed anymore

我正在使用它将自定义内存数据hdr从vfw相机传送到内存流中,以便我可以使用TJPEGImage类正确解码它,而不是将数据写入文件并在每个帧中重新加载它...
这里是另一个例子:
class A
    {
protected:
    int x;
public:
    int getx(){ return x; }
    };

class hack_A:A
    {
public:
    void setx(int _x){ x=_x; }
    };

void test()
    {
    A a;
    hack_A *ha=(hack_A*)&a;
    ha->setx(10);
    a.getx(); // print the x somwhere
    }

然而,这对私有成员无效...在这种情况下,也可以实现,但需要访问 A 源代码。
class A
    {
protected:
    int x;
private:
    int y;
public:
    int getx(){ return x; }
    int gety(){ return y; }
    friend class hack_A;        // but this one requires access to A soourcecode
    };

class hack_A:A
    {
public:
    void setx(int _x){ x=_x; }
    void sety(int _y){ y=_y; }
    };

void test()
    {
    A a;
    hack_A *ha=(hack_A*)&a;
    ha->setx(10);
    ha->sety(20);
    a.getx(); // print the x somwhere
    a.gety(); // print the x somwhere
    }

很好了解。但在我的情况下不起作用,因为我将不得不重新实现InternalSetLocation,它需要访问私有字段(而不是方法)。 - Gabriel
@rigel 你只需要在派生类中编写setter...就像我在我的类中添加了SetMemory一样... - Spektre
你的意思是,在我的派生类中重新声明FPushed并编写一个getter和setter吗?你可能有道理,但我不太明白。 - Gabriel
@Rigel 我添加了另一个例子,更好地模仿了你所描述的内容。 - Spektre
@Rigel 看看最后一个例子...在这种情况下,唯一的方法是将您的黑客类添加为友元...修改 VCL/FMX。 - Spektre
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接