2014-09-18 50 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; 

至於多態性,你可以真的只是自己測試一下。助手將適用於任何派生類您的實例派生自:

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

// ... 

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

其中當與助手上面的基類叫做

TSpecific2 = class(TSpecific1) 
end; 

會產生輸出specific 1

注意
德爾福10.1柏林出發,類助手不再能夠訪問受保護的嚴格,嚴謹的私人或私有成員。這個「功能」實際上是Embarcadero現在在柏林修復的一個編譯器錯誤。
使用助手訪問普通保護成員仍然是可能的。

+0

謝謝!那麼,在避免遞歸的同時不可能保留原始方法的名稱? – 2014-09-18 17:10:00

+0

並且多態性能否在不涉及'TSpecificN'實現的可怕細節的情況下工作?例如:助手能夠調用虛擬方法嗎? – 2014-09-18 17:16:44

+0

@FreeConsulting不,如果您嘗試使用相同的名稱,堆棧溢出應該非常明顯。編輯回答你的第二個問題。 – 2014-09-18 17:22:10

相關問題