2014-09-18 2 views
3

한다고 가정 우리는 잠재적으로 매우 유용 방법과 클래스를 가지고 있지만 사용할 수 없습니다 때문에 보호 범위 :클래스 도우미를 사용하여 보호 된 메서드를 호출하려면 어떻게해야합니까?

unit Sealed; 

interface 

type 
    TGeneral = class(TObject) 
    { this method is useful, but not available } 
    protected procedure Useful; virtual; 
    end; 

    TSpecific1 = class(TGeneral) 
    { some descendants override `Useful` method } 
    protected procedure Useful; override; 
    end; 

    TSpecific2 = class(TGeneral) 
    { and some dont, but inherit `Useful`ness from the parent } 
    end; 

나는, 모두 상속과 배역을 포함하는 등의 방법을 위해 밖으로 도달하는 방법은 두 구식 방법을 알고 . 두 접근법 모두 기본 사례 # 1 및 고급 다형 사례 # 2와 동일하게 작동해야합니다.

program CallingSite; 

uses Sealed; 

function GetInstance: TGeneral; 
begin 
    { !PSEUDO! makes compiler happy about the rest of code } 
    // depending on use case supposed to return an instance of `TGeneral` 
    // or any of its descendants - `TSpecific1`, `TSpecific2` 
end; 

type 
    { this makes a current module a "friend" for `TGeneral` } 
    TFriend = class(TGeneral) 
    end; 

procedure Case1; 
var 
    { holds an instance of `TGeneral` } 
    General: TGeneral; 
begin 
    General := GetInstance; 
    { protected method is available for "friend" via static cast } 
    TFriend(General).Useful; // compiles! 
end; 

type 
    TIntroducer = class(TGeneral) 
    { this "reintroduces" `Useful` method to public scope } 
    public procedure Useful; override; 
    // this approach ought to work even with strict protected methods 
    // !!! but I THINK it is UNSAFE to use on virtual and/or dynamic methods 
    end; 

procedure TIntroducer.Useful; 
begin 
    { and calls `Useful` via wrapper } 
    inherited; 
end; 

procedure Case2; 
var 
    { polymorphic instance of any `TGeneral`'s descendant } 
    Specific: TGeneral; 
begin 
    Specific := GetInstance; 
    { protected method is callable via public wrapper, static cast again } 
    TIntroducer(Specific).Useful; // compiles! 
end; 

내가 알고 싶습니다

  • 어떻게 클래스 헬퍼의 전원을인가 같은 결과를 달성하기 위해?
  • 클래스 도우미와 함께 개인 메서드를 호출 할 수 있습니까?
  • 은 클래스 도우미가 내부 범위가 아닌 클래스 범위를 증가시키기 때문에 사례 # 1과 사례 # 2의 차이점이 있습니까?
  • 재귀 위험없이 클래스 도우미에서 다시 도입 된 원본 메서드를 호출하는 방법은 무엇입니까?

또한 TIntroducer 안전하지 않은 의견에 대해 의견을 말하십시오.

답변

5

당신은 그래서 도우미를 사용할 수 있습니다

unit Unit2; 

interface 

type 
    TGeneral = class(TObject) 
    protected procedure Useful; virtual; 
    end; 

    TSpecific2 = class(TGeneral) 
    end; 

    TSpecificHelper = class helper for TGeneral 
    public 
    procedure ExposedUseful; 
    end; 

implementation 

procedure TGeneral.Useful; 
begin 
    WriteLn('general'); 
end; 

procedure TSpecificHelper.ExposedUseful; 
begin 
    Useful; 
end;  

end. 

이 심지어 예를 들어, 별도의 단위로 선언 할 수 있습니다 :

unit Unit2; 

interface 

type 
    TGeneral = class(TObject) 
    protected procedure Useful; virtual; 
    end; 

implementation 

procedure TGeneral.Useful; 
begin 
    WriteLn('general'); 
end; 

end. 

별도로

unit Unit3; 

interface 
uses 
    Unit2; 
type 
    TSpecific2 = class(TGeneral) 
    end; 

    TSpecificHelper = class helper for TGeneral 
    public 
    procedure ExposedUseful; 
    end; 

implementation 

procedure TSpecificHelper.ExposedUseful; 
begin 
    Useful; 
end; 

end. 

그리고 테스트하기 :

program Project1; 


{$APPTYPE CONSOLE} 

uses 
    //Unit2, // either or 
    Unit3; 

var 
    foo : TSpecific2; 
begin 
    foo := TSpecific2.Create; 
    foo.ExposedUseful; 
    Readln; 
end. 

기본 클래스의 도우미를 대신 작성하면 개인 멤버도 비슷한 방식으로 노출 될 수 있습니다. 그러나 다른 유닛에 있다면 캐스트가 필요합니다. 예 :

// in Unit2 
TGeneral = class(TObject) 
    private 
     procedure AlsoUseful; 
    protected 
     procedure Useful; virtual; 
    end; 

//in Unit3 

    TSpecificHelper = class helper for TGeneral 
    public 
    procedure ExposedUseful; 
    procedure ExposedAlsoUseful; 
    end; 

// ... 
implementation 

procedure TSpecificHelper.ExposedAlsoUseful; 
begin 
    TGeneral(self).AlsoUseful; 
end; 

다형성은 실제로 직접 테스트 할 수 있습니다. 도우미는 인스턴스에서 파생 어떤 하위 클래스에 적용됩니다 : 위의 기본 클래스의 도우미를 호출 할 때

TSpecific2 = class(TSpecific1) 
end; 

출력 specific 1를 생성합니다

TSpecific1 = class(TGeneral) 
    protected 
     procedure Useful; override; 
    end; 

// ... 

procedure TSpecific1.Useful; 
begin 
    WriteLn('specific 1'); 
end; 

. 델파이 10.1 베를린을 시작으로


, 클래스 헬퍼는 더 이상 엄격한 보호, 엄격한 개인 또는 개인 회원에 액세스 할 수 없습니다. 이 "기능"은 실제로 Embarcadero가 베를린에서 수정 한 컴파일러 버그였습니다.
헬퍼가있는 평범한 보호 된 멤버에게 액세스하는 것이 가능합니다.

+0

고마워요! 재귀를 피하면서 원래 메소드 이름을 유지하는 것은 불가능합니다. –

+0

다형성은'TSpecificN' 구현에 대한 끔찍한 세부 사항없이 작동 할 것인가? 예 : 도우미가 가상 메소드를 호출 할 수 있습니까? –

+0

@FreeConsulting 아니요, 같은 이름을 사용하려고하면 스택 오버플로가 명확해야합니다. 두 번째 질문에 답하기 위해 편집 됨. –

관련 문제