【发布时间】:2014-08-18 17:25:25
【问题描述】:
由于 Delphi 中缺少多重继承,我需要使用接口委托。这对我来说是一个非常新的话题,我在将覆盖与接口委托结合使用时遇到了问题。
TMyNode 类必须继承自TBaseClass,并且需要实现IAddedStuff。我想在TAddedStuffDefaultImplementation 中拥有IAddedStuff 的所有功能的默认实现,所以我不需要到处都有getter/setter 的重复代码。所以,我已经使用DefaultBehavior 委派了这些事情。
问题是,TAddedStuffDefaultImplementation 意味着有虚拟方法,所以我想直接在 TMyNode 中覆盖它们。如果我写 FDefaultImplementation: TAddedStuffDefaultImplementation; 而不是 FDefaultImplementation: IAddedStuff; ,这确实有效。
但是现在,由于某些原因TAddedStuffDefaultImplementation 会增加x: TBaseClass; 的 Ref-Counter,所以它不能被释放。我该怎么办?
我的简化复制代码如下:
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
IAddedStuff = interface(IInterface)
['{9D5B00D0-E317-41A7-8CC7-3934DF785A39}']
function GetCaption: string; {virtual;}
end;
TAddedStuffDefaultImplementation = class(TInterfacedObject, IAddedStuff)
function GetCaption: string; virtual;
end;
TBaseClass = class(TInterfacedObject);
TMyNode = class(TBaseClass, IAddedStuff)
private
FDefaultImplementation: TAddedStuffDefaultImplementation;
public
property DefaultBehavior: TAddedStuffDefaultImplementation read FDefaultImplementation
write FDefaultImplementation implements IAddedStuff;
destructor Destroy; override;
// -- IAddedStuff
// Here are some functions which I want to "override" in TMyNode.
// All functions not declared here, should be taken from FDefaultImplementation .
function GetCaption: string; {override;}
end;
{ TAddedStuffDefaultImplementation }
function TAddedStuffDefaultImplementation.GetCaption: string;
begin
result := 'PROBLEM: CAPTION NOT OVERRIDDEN';
end;
{ TMyNode }
destructor TMyNode.Destroy;
begin
if Assigned(FDefaultImplementation) then
begin
FDefaultImplementation.Free;
FDefaultImplementation := nil;
end;
inherited;
end;
function TMyNode.GetCaption: string;
begin
Result := 'OK: Caption overridden';
end;
var
x: TBaseClass;
gn: IAddedStuff;
s: string;
begin
x := TMyNode.Create;
try
TMyNode(x).DefaultBehavior := TAddedStuffDefaultImplementation.Create;
Assert(Supports(x, IAddedStuff, gn));
WriteLn(gn.GetCaption);
finally
WriteLn('RefCount = ', x.RefCount);
// x.Free; // <-- FREE fails since FRefCount is 1
end;
ReadLn(s);
end.
【问题讨论】:
-
我不熟悉接口,但我有一个问题。
TMyNode继承TBaseClass和IAddedStuff。TBaseClass继承TInterfacedObject,TAddedStuffDef....也继承TInterfacedObject和IAddedStuff所以基本上如果 TMyNode 继承TAddedStuffDef....不应该具有相同的功能集吗?对我来说似乎是双重的,但也许我错了:) -
TMyNode 需要从 TAddedStuffDefaultImplementation AND TBaseClass 继承。由于多重继承是不可能的,我需要做上面的所有事情。 :-( 在我的简化示例中,TBaseClass 没有其他内容,因为它与问题无关。
-
文档使用接口,而您的代码使用类引用——混合使用是引用计数问题的常见来源。
-
TInterfacedObject 的锚是引用计数的(除非你改变它)并且永远不应该被释放。
-
好的,让我澄清一下。 TInterfacedObject 的 Achestor 使用引用计数实现接口,并且这些对象实例的生命周期由这些接口的引用计数控制。你不应该在这些对象上使用 Free。这与不实现引用计数的 TInterfacedPersistent 不同。
标签: delphi oop interface delegation