我不知道我是否需要或如何实现接口的这 3 个基本方法

I don't know if I need to or how to implement those 3 basic methods of an interface

我想实现一个接口,但我不能从 TInterfacedObject 声明它,在这种情况下,文档说我必须实现 QueryInterface_AddRef_Release.但我不确定这是否是强制性的。到目前为止我还没有真正使用过接口... They say 一些关于 COM 对象的东西,但我什至不知道那是什么意思。我从未有意使用 COM 对象,也许只有当它们包含在我从互联网上获取的某些代码片段中时才使用。我尝试了一个例子(见下文),它在没有实现这 3 种方法的情况下工作。所以...

  1. 我怎么知道我是否必须实施它们?
  2. 如果我必须实施它们,我该怎么做?我不知道这些方法应该做什么。我应该从 TInterfacedObject 复制实现吗? (其实不止3个。。。多出来的也得抄?)

谢谢!

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type

  IShellInterface = interface
  ['{55967E6B-5309-4AD0-B6E6-739D97A50626}']
   procedure SetPath(const APath: String);
   function GetPath: String;
  end;

  TDriveBar = class(TCustomPanel, IShellInterface)
  private
   FDriveLink: IShellInterface;
   FPath: String;
  public
   procedure SetPath(const APath: String);
   function  GetPath: String;
   property  DriveLink: IShellInterface read FDriveLink write FDriveLink;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    DriveBar1, DriveBar2: TDriveBar;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TDriveBar.SetPath(const APath: String);
begin
 FPath:= APath;
 Caption:= APath;
end;

function TDriveBar.GetPath: String;
begin
 Result:= FPath;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
 ReportMemoryLeaksOnShutdown:= True;

 DriveBar1:= TDriveBar.Create(Form1);
 DriveBar1.Parent:= Form1;
 DriveBar1.SetBounds(20, 20, 250, 40);
 DriveBar1.SetPath('Drive Bar 1');

 DriveBar2:= TDriveBar.Create(Form1);
 DriveBar2.Parent:= Form1;
 DriveBar2.SetBounds(20, 80, 250, 40);
 DriveBar2.SetPath('Drive Bar 2');

 DriveBar1.DriveLink:= DriveBar2;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 DriveBar1.DriveLink.SetPath('D:\Software\Test');
 Caption:= DriveBar2.GetPath;
end;

end.

任何支持接口的class必须实现所有三种方法:

function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;

如果您继承自的基 class 实现了这些方法,则您不需要实现它们。如果基础 class 没有它们,您的代码将无法编译。

不同的 classes 对这些方法和主要方法有不同的实现,最重要的区别是是否启用自动引用计数。

如果启用了引用计数,那么你应该始终将此类class的实例存储在接口引用中(变量类型必须是接口),如果禁用,则可以使用对象引用。

启用ARC会自动管理此类实例的内存,禁用则需要手动释放此类实例。

例如,启用引用计数的 class 是 TInterfacedObject,禁用引用计数的 class 大多数情况下是 TComponent(除非它服务于作为 COM 对象容器)。

基本上,在最简单的情况下,如果 _AddRef_Release 只是 return -1 那么引用计数将被禁用。如果你需要实现引用计数,那么复制代码或继承的最佳模板是 TInterfacedObject.

QueryInterface 的目的是为 Support 函数添加功能并查询支持的 GUID 的接口。如果不确定要放什么,无论是否启用 ARC,都可以使用 TInterfacedObject 实现。

也有可能 class 可以根据传递给构造函数的相同值禁用或启用 ARC。 class 的示例是 TXMLDocument,其中如果 nil 作为 Owner 启用 ARC,否则 ARC 将被禁用。


在您的示例中,TCustomPanel 继承自 TComponent,后者已经实现了这些方法,因此您无需执行任何操作。