2014-09-18 51 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

相关问题