由于Delphi中缺少多重继承,我需要使用接口委派。这对我来说是一个非常新的主题,我在将重写与接口委派相结合时遇到了问题。
班级TMyNode
必须从TBaseClass
继承,并且需要实施IAddedStuff
。我想在IAddedStuff
中使用TAddedStuffDefaultImplementation
的所有函数的默认实现,因此我不需要在任何地方都有重复的getter / setter代码。所以,我已经使用DefaultBehavior
委派了这些内容。
问题是,TAddedStuffDefaultImplementation
意味着拥有虚拟方法,所以我想直接在TMyNode
中覆盖它们。如果我写FDefaultImplementation: TAddedStuffDefaultImplementation;
而不是FDefaultImplementation: IAddedStuff;
,这确实有用。
但是现在,由于某些原因,TAddedStuffDefaultImplementation
会增加x: TBaseClass;
的参考计数器,因此无法释放它。我该怎么办?
我的简化复制代码如下:
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.
答案 0 :(得分:5)
如果您委派IAddedStuff
,那么您还应该在另一个类上实现非默认行为,并通过构造函数注入传递它。
此外,如果要混合对象和接口引用,请确保引用计数不会发生冲突。使用接口委派时,容器对象的引用会发生变化。
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.