DELPHI虽然很好,但目前不流行,所以相关的资料相对比较少,以前我也是花了不少时间才有所得。
为了方便同行,有时间我会把一些经验在这里和大家分享。
用过的都知道,在DELPHI WIN32下使用接口会有点复杂。一般通过继承TInterfacedObject来实现接口,而TInterfacedObject子类实例是由DELPHI根据引用计数来自动管理释放的。稍不注意,很容易出现异常。
所以使用DELPHI的接口要注意以下事项:
1.当使用接口变量时,如:p:Interface,要注意p的生命期。
在方法内部定义的p,方法执行结束时,p的生命期才算结束。
定义全局的p,只有在应用退出时,p的生命期才算结束。
在类内定义p作为属性,只有该类实例释放时,p才算用完。
所以如果p引用的对象在p的生命期结束前就释放了,很容易出现一些莫名其妙的异常。
当然,你在用完p后能 p:=nil,是一个好的习惯。
2.对于表达式: (对象 as 接口).方法(..) ,可以认为DELPHI会产生一个局部的接口变量,所以如果对象在这局部范围退出前会被释放的话,退出局部范围时会触发异常。解决的办法是:p := 对象 as 接口,显式使用接口变量,用完就设为NIL。
3.尽量把接口作为参数。譬如:定义一过程 procedure aaa(const p:Interface) ;,如果使用时是:aaa(TTestClass.Create(..)),那么肯定会导致内存泄漏。
4.TInterfacedObject及其子类的实例,在创建后若未赋值给任何接口变量,需要手动释放。
这里介绍两个类,或许对你有用。
1.TCommonInterfaced。继承它可以实现接口,特点是屏蔽DELPHI的自动管理,由开发人员来手动管理实例的释放。
2.TEventInterfaced。继承它可以实现接口,特点是在激活实例的自动释放功能后,实例会在外部用完时由DELPHI来释放;若没有激活自动释放功能,则手动释放。这个类主要用在事件模型下,类似于JAVA的事件模型,监听器是以接口形式挂在事件源上的,只有当事件源撤销后,监听器才能释放。所以,如果监听器是继承自 TEventInterfaced,那么事件源在撤销前激活监听器的自动释放功能,那么DELPHI就能选择适当的时机释放监听器了。
源代码如下:
********************************************************************
unit euBase;
interface
uses Classes,SysUtils ;
Type
//普通的接口对象。当接口不再使用时不会自动释放对象。
TCommonInterfaced = class(TInterfacedObject)
protected
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
end;
//专用在事件模型的接口对象。
//所以当需要释放实现接口的对象时,只要激活接口的自动释放功能,对象就会在不使用接口时自动释放
IEventInterface = interface(IInterface)
['{4A8C144E-07B9-4357-8BF0-EE57D2F69888}']
procedure ReleaseInIdle;
end;
{
专用在事件模型的接口对象。
当需要释放实现接口的对象时,只要激活接口的自动释放功能,
对象就会在不使用接口时自动释放。
}
TEventInterfaced = class(TInterfacedObject, IEventInterface)
private
mAutoRelease: Boolean;
procedure ReleaseInIdle;
protected
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
end;
implementation
{ TCommonInterface }
{
****************************** TCommonInterfaced *******************************
}
procedure TCommonInterfaced.AfterConstruction;
begin
end;
procedure TCommonInterfaced.BeforeDestruction;
begin
end;
function TCommonInterfaced._AddRef: Integer;
begin
Result:=1 ;
end;
function TCommonInterfaced._Release: Integer;
begin
Result:=1 ;
end;
{ TEventInterface }
{
******************************* TEventInterfaced *******************************
}
procedure TEventInterfaced.AfterConstruction;
begin
inherited;
mAutoRelease:=false ;
end;
procedure TEventInterfaced.BeforeDestruction;
begin
inherited;
end;
procedure TEventInterfaced.ReleaseInIdle;
begin
mAutoRelease:=true ;
end;
function TEventInterfaced._AddRef: Integer;
begin
if (RefCount=0) and (mAutoRelease=false) then Inherited _AddRef() ;
Result:=Inherited _AddRef() ;
end;
function TEventInterfaced._Release: Integer;
begin
if (RefCount=2) and (mAutoRelease=true) then
begin
Inherited _Release() ;
Result:=Inherited _Release() ;
end
else if (RefCount<>1) or (mAutoRelease=true) then
Result:=Inherited _Release()
else
Result:=Inherited _Release() ;
end;
end.
*******************************************************************
USE的单元可能需要补充,因为源代码是摘录的。
介绍两个在DELPHI下支持接口的类
最新推荐文章于 2023-08-25 11:54:40 发布