문제

저는 최근 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에서는 실패합니다.2007년 상속 체인 살펴보기 TBitBtn 에서 파생되는 데 사용 TButton.따라서 모든 버튼 컨트롤에서 예상되는 이벤트(예:OnClick)을(를) 공유했습니다. TButton 수업.그래서 치료를 받을 수 있었어요 TBitBtn 수업을 TButton.

2007년 상속 체인:

  • TBitBtn :T버튼

2009년 상속 체인:

  • TBitBtn :TCustomButton
  • T버튼 :TCustomButton

2009년에는 두 사람 모두 T버튼 그리고 TBit버튼 ~에서 유래하다 TCustomButton, 속성과 같은 버튼이 거기에 있으면 괜찮을 것 같습니다.그렇다면 다음 문제를 처리하도록 코드를 변경할 수 있습니다. TCustomButton 대신에.안타깝게도, TCustomButton 다음과 같은 것을 보유하지 않습니다 온클릭.그러므로 더 이상 치료할 수 없습니다. TBitBtn 같은 T버튼.이제 이 두 클래스 모두 속성과 같은 별도의 버튼을 갖습니다(예:둘 다 자체 OnClick 이벤트가 선언되어 있습니다.내 말은, 최소한 인터페이스 같은 것을 제공하라는 거죠. I버튼 둘 다 T버튼 그리고 TBitBtn 구현하다.

이러한 유형의 겉으로는 무해해 보이는 변화가 불필요한 혼란을 초래할 수 있는 것 같습니다.이것은 이상해 보이며 CodeGear(또는 해당 문제에 대한 프레임워크 작성자)가 이런 유형의 작업을 수행하는 이유를 아는 사람이 있는지 궁금합니다.

더 중요한 것은 이렇게 조각난 상속이 있다는 것입니다. 우아한 치료하는 솔루션 TBitBtn 같은 T버튼?

도움이 되었습니까?

해결책

TButton과 TBitBtn은 처음부터 TControl 수준까지 구현되어 항상 그랬기 때문에 여전히 공통 OnClick 이벤트를 계속해서 공유합니다.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를 사용하는 것입니다. 이를 통해 자체 OnClick 이벤트가 있는 TSpeedButton과 같은 다른 유형의 객체도 처리할 수 있습니다. 즉:

#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
    }
};

다른 팁

이것이 델파이라면, 나는 tcustombutton 클래스를 ~이다 그리고 ~처럼 운영자 :

if (SrcButton is TButton) then
  (SrcButton as TButton).OnClick := OnButtonClick
else if (SrcButton is TBitButton)
  (SrcButton as TBitButton).OnClick := OnButtonClick;

C ++는 너무 오래 전에입니다

BTW, VCL에는 버튼, 메뉴 등과 호출 된 코드 사이에 단일 인터페이스를 제공하는 작업이 포함되지 않았습니까?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top