Существует ли базовый класс, не содержащий ссылок, например TInterfacedObject?
Мне нужен базовый класс, например TInterfacedObject
, но без подсчета ссылок (так что это вид TNonRefCountedInterfacedObject
).
Это на самом деле в n-й раз, когда мне нужен такой класс, и как-то я всегда заканчиваю писать (читай: копировать и вставлять) свои собственные снова и снова. Я не могу поверить, что нет "официального" базового класса, который я могу использовать.
Есть ли базовый класс где-то в RTL, реализующем IInterface
, но без подсчета ссылок, который я могу получить из своих классов?
Ответы
Ответ 1
В модуле Generics.Defaults определен класс TSingletonImplementation. Доступно в Delphi 2009 и выше.
// A non-reference-counted IInterface implementation.
TSingletonImplementation = class(TObject, IInterface)
protected
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
Ответ 2
Я сделал это. Его можно использовать вместо TInterfacedObject с подсчетом ссылок или без него. Он также имеет свойство name - очень полезно при отладке.
// TArtInterfacedObject
// =============================================================================
// An object that supports interfaces, allowing naming and optional reference counting
type
TArtInterfacedObject = class( TInterfacedObject )
constructor Create( AReferenceCounted : boolean = True);
PRIVATE
FName : string;
FReferenceCounted : boolean;
PROTECTED
procedure SetName( const AName : string ); virtual;
PUBLIC
property Name : string
read FName
write SetName;
function QueryInterface(const AGUID : TGUID; out Obj): HResult; stdcall;
function SupportsInterface( const AGUID : TGUID ) : boolean;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
// =============================================================================
{ TArtInterfacedObject }
constructor TArtInterfacedObject.Create( AReferenceCounted : boolean = True);
begin
inherited Create;
FName := '';
FReferenceCounted := AReferenceCounted;
end;
function TArtInterfacedObject.QueryInterface(const AGUID: TGUID; out Obj): HResult;
const
E_NOINTERFACE = HResult($80004002);
begin
If FReferenceCounted then
Result := inherited QueryInterface( AGUID, Obj )
else
if GetInterface(AGUID, Obj) then Result := 0 else Result := E_NOINTERFACE;
end;
procedure TArtInterfacedObject.SetName(const AName: string);
begin
FName := AName;
end;
function TArtInterfacedObject.SupportsInterface(
const AGUID: TGUID): boolean;
var
P : TObject;
begin
Result := QueryInterface( AGUID, P ) = S_OK;
end;
function TArtInterfacedObject._AddRef: Integer;
begin
If FReferenceCounted then
Result := inherited _AddRef
else
Result := -1 // -1 indicates no reference counting is taking place
end;
function TArtInterfacedObject._Release: Integer;
begin
If FReferenceCounted then
Result := inherited _Release
else
Result := -1 // -1 indicates no reference counting is taking place
end;
// =============================================================================
Ответ 3
Вы можете рассмотреть TInterfacedPersistent. Если вы не переопределяете GetOwner, он не выполняет подсчет ссылок.
Ответ 4
Я не знаю какого-либо базового класса, поэтому я написал свой собственный (как вы). Просто поставьте его в единый блок utils, и все готово.
type
TPureInterfacedObject = class(TObject, IInterface)
protected
{ IInterface }
function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
{ TPureInterfacedObject }
function TPureInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
Result := E_NOINTERFACE;
end;
function TPureInterfacedObject._AddRef: Integer;
begin
Result := -1;
end;
function TPureInterfacedObject._Release: Integer;
begin
Result := -1;
end;
Ответ 5
Нет такого класса, но вы можете легко написать свои собственные, как показали другие. Однако я задаюсь вопросом, зачем вам это нужно. По моему опыту, редко существует настоящая потребность в таком классе, даже если вы хотите смешивать ссылки на объекты и интерфейсы.
Также обратите внимание, что при использовании такого класса вам все равно придется позаботиться о том, чтобы установить любые ссылки на интерфейс, которые у вас есть на такой объект, до нуля, прежде чем они покинут область действия и до того, как вы освободите объект. В противном случае вы можете получить ситуацию, когда среда выполнения пытается вызвать _Release на освобожденном объекте, и это приводит к возникновению недопустимого исключения указателя.
IOW, я бы посоветовал против использовать такой класс вообще.