IType = interface(IUnKnown) function GetTypeName() : string ; end;これを実装したクラスを用意します。
THuman = class(TInterfacedObject,IType) .... function GetTypeName() : string ; // get 'Human' end ; TAnimal = class(TInterfacedObject,IType) .... function GetTypeName() : string ; // get 'Animal' end ; TFish = class(TInterfacedObject,IType) .... function GetTypeName() : string ; // get 'Fish' end ;これらを利用して次のようなTypeNameを取得する関数を作りたいと考えます。
function GetTypeName(intf : IType) : String ; begin exit(intf.GetTypeName()) ; end;GetTypeName(...)関数は引数のintfからGetTypeName()を実行し、TypeNameを取得したいと考えいます。たとえば、以下のようにTHumanのインスタンスオブジェクトを引数に入力すると、'Human'と返すなどです。しかし、ここで問題が分ります。
human := THuman.Create() ; Writeln(GetTypeName(human)) ; // print out 'Human' ......ここで使っているInterfaceは参照カウンタ付きのInterfaceのため、GetTypeName(...)関数の中でhumanオブジェクトは解放されてしまいます。となると、GetTypeName(...)を抜けると、humanは解放されているため、混乱や問題が生じる可能性があります。
このような場合は参照カウンターを無効にしたInterfaceを使えば解放される心配はありません。
(2011/11/24 参照カウンターが無効になるように実装しているクラスがDELPHIには用意されていました - TSingletonImplementation というクラスでGenerics.Defautsにあります)
次のような感じでしょうか。
TNonRefInterfacedObject = class(TObject, IInterface) protected function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end; ... function TNonRefInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult; begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; function TNonRefInterfacedObject._AddRef: Integer; begin exit(-1) ; end; function TNonRefInterfacedObject._Release: Integer; begin exit(-1) ; end;
この場合、_AddRefが呼ばれても_Releaseが呼ばれても参照カウンターは変化しません。
次ももう少しだけDELPHIのInterfaceを使ってみます。
ソースコードは自由にご使用ください。ただし問題が起きても責任はとれません。
0 件のコメント:
コメントを投稿