中国开发网: 论坛: Delphi/BCB: 贴子 284156
pcplayer
Delphi 的接口
TLjnInterfacedObject = class(TObject, IInterface)
protected
FRefCount: Integer;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
class function NewInstance: TObject; override;
property RefCount: Integer read FRefCount;
end;

{ TLjnInterfacedObject }

function TLjnInterfacedObject._AddRef: Integer;
begin
//Result := InterlockedIncrement(FRefCount);
Result:=-1;
end;

function TLjnInterfacedObject._Release: Integer;
begin
{Result := InterlockedDecrement(FRefCount);
if Result = 0 then
Destroy;
}
Result:=-1;
end;

procedure TLjnInterfacedObject.AfterConstruction;
begin

InterlockedDecrement(FRefCount);
end;

procedure TLjnInterfacedObject.BeforeDestruction;
begin
// if RefCount <> 0 then
// System.Error(reInvalidPtr);

end;

class function TLjnInterfacedObject.NewInstance: TObject;
begin
Result := inherited NewInstance;
TLjnInterfacedObject(Result).FRefCount := 1;
end;

function TLjnInterfacedObject.QueryInterface(const IID: TGUID;
out Obj): HResult;
begin
if GetInterface(IID, Obj) then
Result := 0
else
Result := E_NOINTERFACE;
end;


上面的代码直接抄自 TInterfacedObject, 然后改动了一点。代码中注释掉的部分是TInterfacedObject 原来有的,注释部分后紧跟的代码是新加的。代码改动的意义在于,释放接口的时候,不释放实现接口的对象;

然后,定义一个自己的类:

TLjnObj=class(TLjnInterfacedObject,ILjnInterface)
public
procedure Hello(S:string);
end;

procedure TLjnObj.Hello(S: string);
begin
ShowMessage(S);
end;

作了上述改动后的类,在使用的时候:

procedure TForm1.Button1Click(Sender: TObject);
var
MyObj:TLjnObj;

MyCom:TComponent;
i:Integer;
S:string;
begin
MyObj:=TLjnObj.Create;

MyInt:=ILjnInterface(MyObj);


{
i:=MyObj.RefCount;
S:=IntToStr(i);
Memo1.Lines.Add(IntToStr(i));

} //但不能在这段代码里,读这个对象的引用计数值。能读到,不过如果读了,则在做 MyObj.Free 的时候会出现 AV错误,或者执行释放的时候不出错,但程序关闭的时候出 AV 错误。如果执行了这段代码,而又在后面执行了释放接口引用的代码 MyInt=nil,然后才释放对象 MyObj.Free 则也不会出错。



MyInt.Hello('haha');

//MyInt:=nil; //可以不释放这个接口引用,直接释放对象 MyObj 不会出 AV 错误。


{
i:=MyObj.RefCount;
S:=IntToStr(i);
Memo1.Lines.Add(IntToStr(i));
}

MyObj.Free;
end;

总结:
1. 接口引用没有释放干净,即没有做 MyInt=nil 的时候:
1.1. 如果只调用了接口方法,没有去读对象的MyObj.RefCount;则可以直接释放对象,不会出错。
1.2. 如果读了对象的接口引用计数值,则释放对象的时候会出错。
1.3. 如果读了对象的接口引用计数值,然后释放了接口 MyInt=nil 然后释放对象,则不会出错。

总结:要想没有释放接口引用就直接释放对象,对象需要改造。而且,这时候还不能读对象的接口引用计数值,否则释放的时候还是会出错。能不能对这个对象做其它操作,还需要做进一步实验。

相关信息:


欢迎光临本社区,您还没有登录,不能发贴子。请在 这里登录