我最近开始将我的 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 );
这一切都用于编译,但在 2009 年它失败了。查看用于从
TBitBtn
派生的 2007 TButton
的继承链。因此,任何按钮控件(即 OnClick)上预期的事件由 TButton
类共享。因此,我能够将我的 TBitBtn
类视为 TButton
。2007 继承链:
2009 继承链:
在 2009 年, TButton 和 TBitButton 都源自 TCustomButton ,我想如果按钮之类的属性保留在那里就好了。如果是这种情况,我可以更改代码以处理 TCustomButton 。不幸的是, TCustomButton 没有像 OnClick 这样的东西。因此,我不能再将 TBitBtn 视为 TButton 。这两个类现在都有自己独立的按钮之类的属性(即它们都声明了自己的 OnClick 事件)。我的意思是,至少提供一个接口(interface)或类似的东西,比如 TButton 和 TBitBtn 实现的 IButton 。
这些看似无害的变化似乎会造成不必要的破坏。这看起来很奇怪,我想知道是否有人知道为什么 CodeGear(或任何框架作者)会做这种事情?
更重要的是,鉴于这种支离 splinter 的继承,是否有优雅的解决方案可以将 TBitBtn 视为 TButton ?
最佳答案
TButton 和 TBitBtn 仍然继续共享一个共同的 OnClick 事件,因为它从一开始就一直在 TControl 级别实现,并且一直如此。 TButton 只是将 protected TControl::OnClick 事件提升为已发布,然后 TBitBtn 将继承该事件。
在 D2009 中,TCustomButton 与其他 TCustom... 类一样,不会将 protected 成员从基类提升为已发布。 TButton 和 TBitBtn 将 protected 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
}
};
或者,对于任何通用的 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
}
};
一个更优雅的解决方案是改用 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
}
};
甚至:
#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
}
};
关于c++ - TBitBtn 和 TButton 继承链发生了什么变化?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/946316/