[转]接口小论

  完成一个功能时用到观察者模式,将业务类的变化通知给外部的窗体,同时也通知给另一个类,假设为TTest,这个类继承自TInterfaceObject。窗体和TTest都实现了一个接口,因此业务类通过接口可以将变化通知给外部。

  感觉这个类层次应用得很好,但问题出现了,业务类用IInterfaceList管理这些接口,程序关闭时,IInterfaceList将所有的接口置为Nil,按以前的理解,实现接口的类对象会同时被消毁。即TTest对象和窗体类对象自动会被消毁。但事实上并不是这样。

  经过一番研究,才明白个中原因,有结论如下:

1.类如果从TInterfaceObject继承下来,并且实现某个接口。

该接口变量可以自动释放实现该接口的类,例子如下:

type

ITest = interface(IInterface)
  procedure test;
end;

TTest = class(TInterfacedObject, ITest)
public
  procedure test;
  destructor Destroy; override;
end;

{TTest}
procedure TTest.test;
begin
  showmessage(‘ok‘);
end;

destructor Destroy; 
begin
  showmessage(‘ok‘);
  inherited;
end;

//测试
var
  Test: ITest;
begin
  Test := TTest.Create;
  try
    Test.test;
  finally
    Test := nil;
  end;
end;

执行后,弹出两次对话框,说明TTest对象最后被释放了,原因是Test := nil 后,最终于会调用TInterfaceObject的_Release方法,在里面如果引用计数为0,则调用Destroy释放自己。

2.  类如果从TComponent继承下来,并且实现某个接口。

该接口变量不能自动释放实现该接口的类,把上面的TTest改为从TComponent继承,测试代码如下:

var
  Test: ITest;
begin
  Test := TTest.Create(nil);
  try
    Test.test;
  finally
    Test := nil;
  end;
end;

  这时只弹出一个对话框,说明对象没有被释放,原因是Test := nil后,最终于会调用TComponent的_Release,而里面如果引用计数为0并不会释放自己。

3.要对象可以由接口自动释放,必须该类自己实现IInterface,并在_Release调用Destroy。例子如下:

type
  ITest = interface(IInterface)
    procedure test;
  end;

TTest = class(TComponent,  IInterface, ITest)
  public
    { IInterface }
    function QueryInterface(const IID: TGUID;
      out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    { ITest }
    procedure test;
    destructor Destroy; override;
  end;
...
{ TTest }

destructor TTest.Destroy;
begin
  ShowMessage(‘ok‘);
  inherited;
end;

function TTest.QueryInterface(const IID: TGUID;
  out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

procedure TTest.test;
begin
  ShowMessage(‘ok‘);
end;

function TTest._AddRef: Integer;
begin
  Result := InterlockedIncrement(FRefCount);
end;

function TTest._Release: Integer;
begin
  Result := InterlockedDecrement(FRefCount);
  if Result = 0 then
    Destroy;
end;

//测试代码
var
  Test: ITest;
begin
  Test := TTest.Create;
  try
    Test.test;
  finally
    Test := nil;
  end;
end;

运行结果,对话框弹了两次,对象可以由接口释放了。

Delphi的接口真是太不直观了。

原文地址:https://www.cnblogs.com/h2zZhou/p/9208303.html

时间: 2024-10-10 01:28:26

[转]接口小论的相关文章

Java 接口小总结;

1.四种基本访问修饰 访问修饰符: 控制访问权限 public 公共的 在不同的包,自己的包都可以使用: default默认的 只能在自己的包中使用: protected 受保护的 不能修饰类 只能在自己的包中使用或者在其他包的子类中使用: private 私有的 不能修饰类 只能在自己的包中自己的类中使用: 2.接口小总结: 将抽象类进行更彻底就是接口,在接口中,所有的方法都是抽象的方法,所有的方法都不提供具体的实现的(比抽象类更抽象的类): 创建接口(在同一个包中,接口名也不能和类文件名相同

Python 登陆接口小程序V1

Python 登陆接口小程序版本V1 Python #!/usr/bin/env python #_*_coding:utf-8 _*_ __author__ = 'gaogd' import MySQLdb as mysql import datetime class Authon(object):     def __init__(self):         self.db = mysql.connect(user="root", passwd="[email prot

微信公众平台消息接口开发 小黄鸡(小贱鸡)机器人 微信公众平台 公众号聊天机器人 ,消息,接口,小黄鸡,小贱鸡,机器人

第一部分 基于模拟请求的方式 一.模拟请求数据 先看一下小黄鸡的网页版界面 我们通过模拟http请求来实现,上面对话抓包如下: 发送消息的包 接收消息的包: 根据上面的包,模拟发起请求如下: 二.与微信对接 小黄鸡还可以使用API方式调用,但免费时间有限,代码和上面基本一样,就不多写了. 三.演示效果 第二部分 基于接口的方式 一.申请小黄鸡接口SimSimi,发音为〝shim-shimee〞,中文翻译:小黄鸡,由韩文simsim(??)演变而成. “??”原意为“无聊”.SimSimi 由IS

接口小总结

不是类,是主要用来描述类具有什么功能,而并不给出每个功能的具体实现 (implements).尤其不能使用new运算符实例化一个接口.一个类可以实现一个或 多个接口,并在需要接口的地方,随时使用实现了响应接口的对象.所有的方法自动地属于public所有的域自动设为public static final接口中绝不能含有实例域,也不能在接口中实现方法.虽然不能构造接口的对象,但是能声明接口的变量:Comparable x:接口变量必须引用实现了接口的类对象:x = new Employee(...)

接口小练习

package jiekou3; public interface Vehicle { public void start(); public void stop(); } package jiekou3; public class Car implements Vehicle { public void start() { System.out.println("开的飞快"); } @Override public void stop() { System.out.println(&

微信接口小例

微信基础类:用于连接微信的API,获取或发送数据. 1 static class WeiXinBase 2 { 3 public static string GetAccessToken(WeiXinConfig config) 4 { 5 string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + config.AppID + "&s

从零接入小程序支付

作者:Jeffchen链接:https://zhuanlan.zhihu.com/p/23594164来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者:Jeffchen链接:知乎专栏来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 小程序中微信支付的能力,是随着小程序的发布一并推出的,然而小程序文档里关于微信支付接口只有一个requestPayment函数的描述. 这个requestPayment函数确实是小程序前端唯一需要调用的

C#-接口

VS接口 小知识 接口和抽象类的区别.接口的可调用权限,都是默认public,不能指定其他可调用权限:抽象类的属性.域.方法用派生类实现,而且不一定都实现,接口用实现接口的类实现,接口声明的所有成员必须都实现:接口可以有实例,通过实现接口的类的实例强制转换过来,调用起来跟类实例一样,抽象类不能有实例. 接口 是一些声明,项目包括属性和方法,用类实现. interface IPerson { int Age; AddAge() { } } 用类实现,必须实现接口的所有项目. class Perso

HDMI接口与协议

深入了解HDMI接口 一.HDMI接口的工作原理这张图是HDMI接口的架构示意图.从左边的信号源中你可以看到,HDMI接口的信源可以是任何支持HDMI输出的设备,而接入端也可以是任何带有HDMI输 入接口的设备.无论他们是音频设备.视频设备还是控制设备,HDMI接口都可以应用其中.在HDMI接口中的数据信号采用的是TMDS最小化传输差分信号协议.这种数据传输协议曾经在DVI接口上得到广泛的应用.而HDMI接口上的数据信号也 沿用了这种协议.这种协议会将标准8bit数据转换为10bit信号,并且在