Подтвердить что ты не робот

Существует ли базовый класс, не содержащий ссылок, например TInterfacedObject?

Мне нужен базовый класс, например TInterfacedObject, но без подсчета ссылок (так что это вид TNonRefCountedInterfacedObject).

Это на самом деле в n-й раз, когда мне нужен такой класс, и как-то я всегда заканчиваю писать (читай: копировать и вставлять) свои собственные снова и снова. Я не могу поверить, что нет "официального" базового класса, который я могу использовать.

Есть ли базовый класс где-то в RTL, реализующем IInterface, но без подсчета ссылок, который я могу получить из своих классов?

4b9b3361

Ответ 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, я бы посоветовал против использовать такой класс вообще.