假设我们有一个类,其方法可能非常有用,但由于 protected 范围而不可用:
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;
我想知道:
- 如何利用类助手的力量获得相同的结果?
- 是否也可以使用类助手调用私有(private)方法?
- 由于类帮助器增强了类作用域而不是内部表示,因此情况 #1 和情况 #2 之间会有任何差异吗?
- 如何从类助手中重新引入的方法调用原始方法而不冒递归风险?
另外,请评论有关 TIntroducer
不安全的评论。
最佳答案
您可以这样使用助手:
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.
如果您为基类创建助手,则可以以类似的方式公开私有(private)成员。如果在不同的单位,则需要 Actor 。例如:
// 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;
使用上述基类的帮助程序调用时,将生成输出特定 1
。
注意
从 Delphi 10.1 Berlin 开始,类助手无法再访问严格 protected 、严格私有(private)或私有(private)成员。这个“功能”实际上是一个编译器错误,Embarcadero 现已在柏林修复。
通过助手访问普通 protected 成员仍然是可能的。
关于delphi - 如何使用类助手调用受保护的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25918233/