TBitBtn和TButton继承链发生了什么变化?

Sco*_*aad 4 c++ vcl c++builder c++builder-2009

我最近开始将我的RAD Studio 2007项目升级到RAD Studio 2009.我注意到的一件事是看似简单的代码突然无法编译.

示例代码:

class CButtonPopupMenu
{
    // Snip

public:
    void Init( TButton* SrcButton )
    {
        SrcButton->OnClick = OnButtonClick;
    }

private:
    void __fastcall OnButtonClick( TObject* Sender )
    {
        // Do some button click stuff
    }
};

// Snip

TButton button = new TButton( this );
TBitBtn bitBtn = new TBitBtn( this );
CButtonPopupMenu popupButton = new CButtonPopupMenu( button );
CButtonPopupMenu popupBitBtn = new CButtonPopupMenu( bitBtn );
Run Code Online (Sandbox Code Playgroud)

这一切都用于编译,但在2009年它失败了.看看2007年的继承链TBitBtn来源于TButton.因此,TButton该类共享任何按钮控件(即OnClick)上预期的事件.因此,我能够把我的TBitBtn班级视为一个TButton.

2007年继承链:

  • TBitBtn:TButton

2009年继承链:

  • TBitBtn:TCustomButton
  • TButton:TCustomButton

在2009年,TButtonTBitButton都来自TCustomButton,如果像属性这样的按钮被保存在那里我会想的很好.如果是这种情况,我可以改为代码来处理TCustomButton.不幸的是,TCustomButton并没有像OnClick这样的东西.因此,我不能再治疗TBitBtnTButton的.这两个类现在都有自己独立的按钮,如属性(即它们都声明了自己的OnClick事件).我的意思是,至少提供一个接口什么的,喜欢的iButton两个TButton的TBitBtn实施.

似乎这些看似无辜的变化可能造成不必要的破坏.这看起来很奇怪,我想知道为什么有人知道为什么CodeGear(或任何框架作者)会做这种事情?

更重要的是,由于这个支离破碎的继承,是存在的,优雅的解决方案来治疗TBitBtnTButton的

Rem*_*eau 7

TButton和TBitBtn仍然继续共享一个共同的OnClick事件,因为它始终在TControl级别实现,并且始终如此.TButton只是将受保护的TControl :: OnClick事件提升为已发布,TBitBtn将继承该事件.

在D2009中,TCustomButton与其他TCustom ...类一样,不会将受保护的成员从基类升级到已发布.TButton和TBitBtn将受保护的TControl :: OnClick事件提升为单独发布.但事件本身仍然存在于TControl级别.

由于它在TControl级别受到保护,因此您可以使用访问者类来访问它,即:

class TCustomButtonAccess
{
public:
    __property OnClick;
};

class CButtonPopupMenu
{
    // Snip

public:
    void Init( TCustomButton* SrcButton )
    {
        ((TCustomButtonAccess*)SrcButton)->OnClick = OnButtonClick;
    }

private:
    void __fastcall OnButtonClick( TObject* Sender )
    {
        // Do some button click stuff
    }
};
Run Code Online (Sandbox Code Playgroud)

或者,对于任何常规TControl指针:

class TControlAccess
{
public:
    __property OnClick;
};

class CControlPopupMenu
{
    // Snip

public:
    void Init( TControl* SrcControl )
    {
        ((TControlAccess*)SrcControl)->OnClick = OnControlClick;
    }

private:
    void __fastcall OnControlClick( TObject* Sender )
    {
        // Do some click stuff
    }
};
Run Code Online (Sandbox Code Playgroud)

更优雅的解决方案是使用RTTI,这也可以让您处理其他类型的对象,例如TSpeedButton,它们有自己的OnClick事件,即:

#include <TypInfo.hpp>

class TControlAccess
{
public:
    __property OnClick;
};

class CControlPopupMenu
{
    // Snip

public:
    void Init( TControl* SrcControl )
    {
        TMethod m;
        m.Code = &OnControlClick;
        m.Data = this;
        SetMethodProp(SrcControl, "OnClick", m);
    }

private:
    void __fastcall OnControlClick( TObject* Sender )
    {
        // Do some click stuff
    }
};
Run Code Online (Sandbox Code Playgroud)

甚至:

#include <TypInfo.hpp>

class CObjectPopupMenu
{
    // Snip

public:
    void Init( TObject* SrcObject )
    {
        TMethod m;
        m.Code = &OnObjectClick;
        m.Data = this;
        SetMethodProp(SrcObject, "OnClick", m);
    }

private:
    void __fastcall OnObjectClick( TObject* Sender )
    {
        // Do some click stuff
    }
};
Run Code Online (Sandbox Code Playgroud)