示例代码:
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年它失败了.看看2007年TBitBtn的继承链是从TButton派生出来的.因此,TButton类共享任何按钮控件(即OnClick)上预期的事件.因此,我能够将TBitBtn类视为TButton.
2007年继承链:
> TBitBtn:TButton
2009年继承链:
> TBitBtn:TCustomButton
> TButton:TCustomButton
在2009年,TButton和TBitButton都来自TCustomButton,如果像属性这样的按钮被保存在那里我会想的很好.如果是这种情况,我可以改为代码来处理TCustomButton.不幸的是,TCustomButton并没有像OnClick这样的东西.因此,我不能再像TButton那样对待TBitBtn了.这两个类现在都有自己独立的按钮,如属性(即它们都声明了自己的OnClick事件).我的意思是,至少提供一个接口或类似的东西,比如TButton和TBitBtn都实现的IButton.
似乎这些看似无辜的变化可能造成不必要的破坏.这看起来很奇怪,我想知道为什么有人知道为什么CodeGear(或任何框架作者)会做这种事情?
更重要的是,鉴于这种分散的遗传,是否有优雅的解决方案来治疗像TButton这样的TBitBtn?
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 } };
或者,对于任何常规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 } };