由于Delphi中缺乏多重继承,我需要使用接口(interface)委托(delegate)。这对我来说是一个非常新的主题,我在将重写与接口(interface)委托(delegate)结合起来时遇到了问题。
类 TMyNode
必须继承自 TBaseClass
并需要实现 IAddedStuff
。我希望在 TAddedStuffDefaultImplementation
中拥有 IAddedStuff
的所有函数的默认实现,因此我不需要到处都有重复的 getter/setter 代码。因此,我使用 DefaultBehavior
委托(delegate)了这些事情。
问题是, 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.
最佳答案
如果您要委托(delegate) IAddedStuff
,那么您还应该在另一个类上实现非默认行为,并通过构造函数注入(inject)传递它。
此外,如果您混合对象和接口(interface)引用,请确保引用计数不冲突。当使用接口(interface)委托(delegate)时,容器对象的引用会发生变化。
program Project1;
{$APPTYPE CONSOLE}
uses
Classes,
SysUtils;
type
IAddedStuff = interface(IInterface)
['{9D5B00D0-E317-41A7-8CC7-3934DF785A39}']
function GetCaption: string; {virtual;}
end;
TAddedStuffDefaultImplementation = class(TInterfacedObject, IAddedStuff)
function GetCaption: string; virtual;
end;
TAddedStuffOverriddenImplementation = class(TAddedStuffDefaultImplementation)
function GetCaption: string; override;
end;
TBaseClass = class(TInterfacedPersistent);
TMyNode = class(TBaseClass, IAddedStuff)
private
FAddedStuff: IAddedStuff;
property AddedStuff: IAddedStuff read FAddedStuff implements IAddedStuff;
public
constructor Create(const addedStuff: IAddedStuff);
end;
{ TAddedStuffDefaultImplementation }
function TAddedStuffDefaultImplementation.GetCaption: string;
begin
result := 'PROBLEM: CAPTION NOT OVERRIDDEN';
end;
{ TAddedStuffOverriddenImplementation }
function TAddedStuffOverriddenImplementation.GetCaption: string;
begin
Result := 'OK: Caption overridden';
end;
{ TMyNode }
constructor TMyNode.Create;
begin
FAddedStuff := addedStuff;
end;
var
x: TBaseClass;
gn: IAddedStuff;
begin
x := TMyNode.Create(TAddedStuffOverriddenImplementation.Create);
try
Assert(Supports(x, IAddedStuff, gn));
WriteLn(gn.GetCaption);
finally
x.Free;
end;
Readln;
ReportMemoryLeaksOnShutdown := True;
end.
编辑:
经过评论中的讨论,我提出以下建议:
program Project1;
{$APPTYPE CONSOLE}
uses
Classes,
SysUtils;
type
IAddedStuff = interface(IInterface)
['{9D5B00D0-E317-41A7-8CC7-3934DF785A39}']
function GetCaption: string;
end;
TAddedStuffDefaultImplementation = class(TInterfacedObject, IAddedStuff)
function GetCaption: string; virtual;
end;
TBaseClass = class(TInterfacedPersistent);
TMyNode = class(TBaseClass, IAddedStuff)
private
FAddedStuff: IAddedStuff;
property AddedStuff: IAddedStuff read FAddedStuff implements IAddedStuff;
public
constructor Create;
end;
TAddedStuffOverriddenImplementation = class(TAddedStuffDefaultImplementation)
private
FMyNode: TMyNode;
public
constructor Create(AMyNode: TMyNode);
function GetCaption: string; override;
end;
{ TAddedStuffDefaultImplementation }
function TAddedStuffDefaultImplementation.GetCaption: string;
begin
result := 'PROBLEM: CAPTION NOT OVERRIDDEN';
end;
{ TMyNode }
constructor TMyNode.Create;
begin
FAddedStuff := TAddedStuffOverriddenImplementation.Create(Self);
end;
{ TAddedStuffOverriddenImplementation }
constructor TAddedStuffOverriddenImplementation.Create(AMyNode: TMyNode);
begin
FMyNode := AMyNode;
end;
function TAddedStuffOverriddenImplementation.GetCaption: string;
begin
Result := 'OK: Caption overridden';
end;
var
x: TBaseClass;
gn: IAddedStuff;
begin
x := TMyNode.Create;
try
Assert(Supports(x, IAddedStuff, gn));
WriteLn(gn.GetCaption);
finally
x.Free;
end;
ReadLn;
ReportMemoryLeaksOnShutdown := True;
end.
关于delphi - 接口(interface)委托(delegate)+重写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24454572/