是否有像 TInterfacedObject 这样的非引用计数基类?

发布于 2024-11-29 17:28:09 字数 258 浏览 1 评论 0原文

我需要一个类似 TInterfacedObject 的基类,但没有引用计数(因此是一种 TNonRefCountedInterfacedObject)。

这实际上是我第n次需要这样的课程,不知怎的,我总是一次又一次地编写(阅读:复制和粘贴)我自己的课程。我不敢相信没有我可以使用的“官方”基类。

RTL 中是否有一个实现 IInterface 的基类,但没有引用计数,我可以从中派生我的类?

I need a base class like TInterfacedObject but without reference counting (so a kind of TNonRefCountedInterfacedObject).

This actually is the nth time I need such a class and somehow I always end up writing (read: copy and pasting) my own again and again. I cannot believe that there is no "official" base class I can use.

Is there a base class somewhere in the RTL implementing IInterface but without reference counting which I can derive my classes from?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

吹泡泡o 2024-12-06 17:28:09

在 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;

In the unit Generics.Defaults there is a class TSingletonImplementation defined. Available in Delphi 2009 and above.

  // 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;
毁梦 2024-12-06 17:28:09

您可以考虑TInterfacedPercient。如果您不重写 GetOwner,它不会进行引用计数。

You might consider TInterfacedPersistent. If you don't override GetOwner it does no ref-counting.

初与友歌 2024-12-06 17:28:09

我这样做了。它可以用来代替 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;


// =============================================================================

I did this. It can be used in place of TInterfacedObject with or without reference counting. It also has a name property - very useful when debugging.

// 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;


// =============================================================================
夏花。依旧 2024-12-06 17:28:09

从 Delphi 11 Embarcadero 开始,将 TNoRefCountObject 添加到系统单元。以下是发行说明中的​​注释:

新类 System.TNoRefCountObject 是非引用计数的
IInterface 实现(替换旧的且命名奇怪的
TSingletonObject)

As of Delphi 11 Embarcadero added TNoRefCountObject to the System unit. Here's the note from the release notes:

The new class System.TNoRefCountObject is a non-reference-counted
IInterface implementation (replacing the old and oddly named
TSingletonObject)

云淡风轻 2024-12-06 17:28:09

我不知道任何开箱即用的基类,所以我编写了自己的基类(像你一样)。只需将其放入通用实用程序单元中即可完成。

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;

I don't know of any out-of-the-box base class, so I wrote my own (like you). Just put it in a common utils unit and you are done.

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;
只为守护你 2024-12-06 17:28:09

没有这样的类,但是您可以轻松编写自己的类,正如其他人所展示的那样。然而,我确实想知道为什么你需要它。根据我的经验,即使您想混合对象和接口引用,也很少真正需要这样的类。

另请注意,当您使用此类时,您仍然需要在此类对象离开作用域之前以及释放对象之前将此类对象的任何接口引用设置为 nil。否则,您可能会遇到运行时尝试在已释放对象上调用 _Release 的情况,这往往会导致无效指针异常。

IOW,我建议反对使用这样的类。

There is no such class, but you can easily write your own, as others have shown. I do, however, wonder why you would need it. In my experience, there is seldom a real need for such a class, even if you want to mix object and interface references.

Also note that when you use such a class, you'll still have to take care of setting any interface references you have to such an object to nil before they leave scope and before you free the object. Otherwise you might get the situation the runtime tries to call _Release on a freed object, and that tends to cause an invalid pointer exception.

IOW, I would advise against using such a class at all.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文