Delphi 接口委托+;最重要的
由于Delphi中缺少多重继承,我需要使用接口委托。这对我来说是一个非常新的主题,我在将重写与接口委托相结合时遇到了一个问题 类Delphi 接口委托+;最重要的,delphi,oop,interface,delegation,Delphi,Oop,Interface,Delegation,由于Delphi中缺少多重继承,我需要使用接口委托。这对我来说是一个非常新的主题,我在将重写与接口委托相结合时遇到了一个问题 类TMyNode必须继承自TBaseClass,并且需要实现IAddedStuff。我希望在TAddedStuffDefaultImplementation中有IAddedStuff的所有函数的默认实现,因此我不需要到处都有重复的getter/setter代码。因此,我使用DefaultBehavior委派了这些事情 问题是,TAddedStuffDefaultImple
TMyNode
必须继承自TBaseClass
,并且需要实现IAddedStuff
。我希望在TAddedStuffDefaultImplementation
中有IAddedStuff
的所有函数的默认实现,因此我不需要到处都有重复的getter/setter代码。因此,我使用DefaultBehavior
委派了这些事情
问题是,TAddedStuffDefaultImplementation
意味着要有虚拟方法,所以我想在TMyNode
中直接重写它们。如果我编写FDefaultImplementation:TAddedStuffDefaultImplementation代码>而不是fdefultimation:IAddedStuff代码>
但是现在,由于某些原因,TAddedStuffDefaultImplementation
将增加x:TBaseClass的Ref计数器代码>,因此无法将其释放。我该怎么办
我的简化复制代码如下:
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.
程序项目2;
{$APPTYPE控制台}
{$R*.res}
使用
System.SysUtils;
类型
IADDestuff=接口(IInterface)
[{9D5B00D0-E317-41A7-8CC7-3934DF785A39}]
函数GetCaption:string;{virtual;}
结束;
TAddedStuffDefaultImplementation=class(TInterfacedObject,IAddedStuff)
函数GetCaption:string;事实上的
结束;
TBASECASE=类别(TInterfacedObject);
TMyNode=class(TBaseClass,IAddedStuff)
私有的
FDefaultImplementation:TAddedStuffDefaultImplementation;
公众的
属性DefaultBehavior:TAddedStuffDefaultImplementation读取FDefaultImplementation
编写fdefultimationimplementation;
毁灭者毁灭;推翻
//--我的东西
//下面是我想在TMyNode中“覆盖”的一些函数。
//此处未声明的所有函数都应取自fdefaultimation。
函数GetCaption:string;{覆盖;}
结束;
{TAddedStuffDefaultImplementation}
函数TAddedStuffDefaultImplementation.GetCaption:string;
开始
结果:='问题:标题未被覆盖';
结束;
{TMyNode}
析构函数TMyNode.Destroy;
开始
如果已分配(FDEFultimation),则
开始
免费;
fdefultimation:=nil;
结束;
继承;
结束;
函数TMyNode.GetCaption:string;
开始
结果:='确定:标题被覆盖';
结束;
变量
x:TBaseClass;
gn:IAddedStuff;
s:字符串;
开始
x:=TMyNode.Create;
尝试
TMyNode(x).DefaultBehavior:=TAddedStuffDefaultImplementation.Create;
Assert(支持(x,IAddedStuff,gn));
WriteLn(gn.GetCaption);
最后
WriteLn('RefCount=',x.RefCount);
//十、免费;// 如果您正在委派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.
我不熟悉界面,但我有一个问题TMyNode
继承了TBaseClass
和IAddedStuff
TBaseClass
继承了TInterfacedObject
,TAddedStuffDef….
也继承了TInterfacedObject
和IadedStuff
所以基本上,如果TMyNode继承了TAddedStuffDef….
的话,它不应该具有相同的函数集吗?对我来说似乎是双重的,但可能我错了:)TMyNode需要从TAddedStuffDefaultImplementation和TBaseClass继承。因为多重继承是不可能的,所以我需要做上面所有的事情:-(在我的简化示例中,TBaseClass没有额外的内容,因为它与问题无关。文档使用接口,而代码使用类引用-混合这是引用计数头痛的常见原因。TInterfacedObject的Anchestor是引用计数的(除非您更改此项)并且永远不应该被释放。好的,让我澄清一下。TInterfacedObject的AcheStor使用引用计数实现接口,这些对象实例的生存期由这些接口的引用计数控制。您永远不应该在这些对象上使用Free。这与TInterfacedPersistent不同,后者不实现引用c装载。非常感谢您的快速回复。我确实混合了对象和接口引用,因为这是进行“覆盖”的唯一可能性工作。由于某些原因,如果专用字段是对象引用,则会调用重写的变量,但当它是接口引用时则不会调用。您的代码解决了引用计数的问题,但遗憾的是,TaddedStuffOverridedImplementation
无法访问TMyNode
。其背后的思想是TAddedStuffDefaultImplementation.GetCaption
只输出“未知”(某个常量),而TMyNode.GetCaption
输出特定于数据的内容,如“User:Thomas”。在TMyNode
中是否还必须有GetCaption
,但仍然覆盖接口的默认实现(主要是getter和setter以及“未知”标题+图标)?您是否创建了TaddedStuff DefaultImplementation
以在不同的其他类中重用它,而无需每次都实现IAddedStuff
?否则,您可以将默认实现方法放在TBaseClasseWithAddedStuff
中,使其虚拟化,然后在TMyNode中重写它们de>。是的,TAddedStuffDefaultImplementation
的目的是与al共享它