对于Object Pascal语言来说,最近一段时间最有意义的改进就是从Delphi3开始支持接口(interface),接口定义了能够与一个对象进行交互操作的一组过程和函数。对一个接口进行定义包含两个方面的内容,一方面是实现这个接口,另一方面是定义接口的客户。一个类能实现多个接口,即提供多个让客户用来控制对象的“表现方式”。

正如名字所表现的,一个接口就是对象和客户通信的接口。这个概念像C++中的PUREVIRTUAL类。实现接口的函数和过程是支持这个接口的类的工作。

在这里你将学到接口的语言元素,要想在应用程序中使用接口,请参考COM和ActiveX方面的资料;

1.定义接口

就像所有的Delphi类都派生于TObject一样,所有的接口都派生于一个被称为是IUnknown的接口,IUnknown在system单元中定义如下:

IDispatch = interface(IUnknown)
['{00020400-0000-0000-C000-000000000046}']
function GetTypeInfoCount(out Count: Integer): HResult; stdcall; 
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; 
function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; 
function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; 
end;

正如你所看到的,接口的定义就像是类的定义,最根本的不同是在接口中有一个全局唯一标识符(GUID),它对于每一个接口来说是不同的。对IUnknown的定义来自于Microsoft的组件对象模型(COM)规范。

如果你知道怎样创建Delphi的类,那么定义一个定制的接口是一件简单的事情,下面的代码定义了一个新的接口称为IFoo,它包含一个被称为F1()的方法:

type
IFoo = Interface
['{2137BF60-AA33-11D0-A9BF-9A4537A42701}'] 
function F1 : Integer; 
end;

提示在Delphi的IDE中,按Ctrl+Shift+G键可以为一个接口生成一个新的GUID。

下面的代码声明了一个称为IBar的接口,它是从IFoo接口继承来的:

type
IFoo = Interface(IFoo)
['{2137BF61-AA33-11D0-A9BF-9A4537A42701}'] 
function F2 : Integer; 
end;

2.实现接口

下面的代码演示了在一个类TFooBar中怎样实现IFoo和IBar接口:

type
TFooBar = class(TInterfacedObject, IFoo, IBar) 
function F1 : Integer; 
function F2 : Integer; 
end;

function TFooBar.F1 : Interger;
begin
Result := 0; 
end;

function TFooBar.F2 : Interger;
begin
Result := 0; 
end;

注意,一个类可以实现多个接口,只要在声明这个类时依次列出要实现的接口。编译器通过名称来把接口中的方法与实现接口的类中的方法对应起来,如果一个类只是声明要实现某个接口,但并没有具体实现这个接口的方法,编译将出错。

如果一个类要实现多个接口,而这些接口中包含同名的方法,必须把同名的方法另取一个别名,请看下面的程序示例:

type
IFoo = Interface 
['{2137BF60-AA33-11D0-A9BF-9A4537A42701}'] 
function F1 : Integer; 
end;

type
IBar = Interface
['{2137BF61-AA33-11D0-A9BF-9A4537A42701}'] 
function F1 : Integer; 
end;

TFooBar = class(TInterfacedObject, IFoo, IBar)
//为同名方法取别名
function IFoo.F1 = FooF1; 
function IBar.F1 = BarF1; 
//接口方法 
function FooF1 : Integer; 
function BarF1 : Integer; 
end;

function TFooBar.FooF1 : Interger;
begin
Result := 0; 
end;

function TFooBar.BarF1 : Interger;
begin
Result := 0; 
end;

3.implements指示符

implements指示符是在Delphi4中引进的,它的作用是委托另一个类或接口来实现接口的某个方法,这个技术有时又被称为委托实现,关于implements指示符的用法,请看下面的代码:

type
TSomeClass = class(TInterfacedObject, IFoo)
//Stuff 
function GetFoo : TFoo; 
property Foo : TFoo read GetFoo implements GetFoo; 
//Stuff 
end;

在上面例子中的implements指示符是要求编译器在Foo属性中寻找实现IFoo接口方法。属性的类型必须是一个类,它包含IFoo方法或类型是IFoo的接口或IFoo派生接口。implements指示符后面可以列出几个接口,彼此用逗号隔开。

implements指示符在开发中提供了两个好处:首先,它允许以无冲突的方式进行接口聚合。聚合

(Aggregation)是COM中的概念。它的作用是把多个类合在一起共同完成一个任务。其次,它能够延后占用实现接口所需的资源,直到确实需要资源。例如,假设实现一个接口需要分配一个1MB的位图,但这个接口很少用到。因此,可能平时你不想实现这个接口,因为它太耗费资源了,用implements指示符后,可以只在属性被访问时才创建一个类来实现接口。

4.使用接口

当在应用程序中使用接口类型的变量时,要用到一些重要的语法规则。最需要记住的是,一个接口是生存期自管理类型的,这意味着,它通常被初始化为nil,它是引用计数的,当获得一个接口时自动增加一个引用计数;当它离开作用域或赋值为nil时它被自动释放。下面的代码演示了一个接口变量的生存期自管理机制。

var
I : ISomeInterface; 
begin

//I被初始化为nil
I := FunctionReturningAnInterface; //I的引用计数加1

I.SomeFunc;

//I的引用计数减1,如果为0,则自动释放。

end;

关于接口变量的另一个规则是,一个接口变量与实现这个接口的类是赋值相容的,例如,下面的代码是合法的:

procedure Test(FB : TFooBar)
var
F : IFoo; 
begin

F :=FB; //合法,因为FB支持IFoo
.

.

最后,类型强制转换运算符as可以把一个接口类型的变量强制类型转换为另一种接口。示例如下:

var
FB : TFooBar; 
F : IFoo; 
B : IBar; 
begin
FB := TFooBar.create;

F :=FB; //合法,因为FB支持IFoo
B := F as IBar; //把F转换为IBar

Delphi 提示在Delphi的IDE中,按Ctrl+Shift+G键可以为一个接口生成一个新的GUID。的更多相关文章

  1. 正则中关于修饰符g以及exec和match区别的一个小demo

    代码: 输出结果 补充: reg.lastIndex:下一次正则捕获的开始查找的索引位置 ->正则的懒惰性就是因为默认情况下lastIndex值都是0,我们不管执行几次exec,都是从字符串的开 ...

  2. sublime 设置像IDE一样的 ctrl+鼠标左键 跳转到定义方法

    鼠标点击菜单栏的Preferences,选择Browse Packages ,进入文件加之后,选择User 点击进入User,在User里面添加文件名为 Default (Windows).subli ...

  3. pycharm中全局搜索ctrl+shift+F快捷键无反应原因和解决

    全局搜索快捷键无反应原因:搜狗输入法占用的ctrl+shift+F快捷键,简繁切换的快捷键.在搜狗输入法中将此项取消.

  4. delphi Ctrl+鼠标左键或者Find Declaration不能定位到源文件

    在Delphi代码编辑器中使用Ctrl+鼠标左键可跳转到鼠标下的类所在的定义处,但今天发现一个奇怪的问题,EhLib组件的类无法跳转(包括uses中的pas文件),重新安装也是如此,后来经过验证,发现 ...

  5. 在IDE中添加widfly依赖

    动机:在IDE中添加widfly依赖 原由:widfly实现了servlet接口,有我们对外交互时所需求的jar包 步骤: 第一步: 找到module依赖的地方 第二步:点击左侧的添加按钮,点击Lib ...

  6. 【转】Android开发中让你省时省力的方法、类、接口

    转载 http://www.toutiao.com/i6362292864885457410/?tt_from=mobile_qq&utm_campaign=client_share& ...

  7. VS2005、VS2008中的快捷键、组合键大全

    Ctrl+E,D ----格式化全部代码 Ctrl+E,F ----格式化选中的代码 CTRL + SHIFT + B生成解决方案 CTRL + F7 生成编译 CTRL + O 打开文件 CTRL ...

  8. java面试一日一题:mysql中的自增主键

    问题:请讲下mysql中的自增主键 分析:该问题主要考察对mysql中自增主键的掌握,使用场景及如何设置 回答要点: 主要从以下几点去考虑 1.什么自增主键 2.使用场景是什么: 3.innodb_a ...

  9. Delphi应用程序的调试(十)调试器选项(在IDE中不要使用异常)

    可在两个级别上设置调试选项:工程级和环境级.在前面的讲解中讲解了工程级调试选项,通过主菜单[Project | Options…]打开如下对话框: 可在Debugger Options对话框中设置全局 ...

随机推荐

  1. React表单元素的使用

    一. <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF ...

  2. DB2中字符、数字和日期类型之间的转换

    DB2中字符.数字和日期类型之间的转换 一般我们在使用DB2或Oracle的过程中,经常会在数字<->字符<->日期三种类 型之间做转换,那么在DB2和Oracle中,他们分别 ...

  3. VNC常用操作及常见问题解决办法汇总

    VNC登录用户缺省是root,但在安装oracle时必须用oracle用户的身份登录,下面我们就以oracle为例说明如何配置VNC,从而可以使用不同的用户登录到主机.步骤描述如下:    步骤一:修 ...

  4. [android警告] AndroidManifest.xml警告 Should explicitly set android:allowBackup to true or false

    http://www.cnblogs.com/javadu/p/3812528.html Android中AndroidManifest.xml警告 Should explicitly set and ...

  5. Windows Services Windows Services的操作

    Windows Services的操作 一.服务的创建: 1.新建项目——Windows服务 2.这是每个人都会犯的错误,新建一个项目后,都会按F5(运行),就会出现如下错误: 3.安装服务有很多种方 ...

  6. WebStorm 对 Mocha 完美支持。

    如果你在使用 Mocha 的话,请使用 WebStorm 来运行 mocha,Webstorm可以清晰查看每个 test 的详细信息,非常直观,强烈推荐.

  7. PowerDesigner15使用时的十五个问题

    15个问题列表: No.1:是不是一定要从CDM开始设计,然后在进行PDM的设计? NO.2:工具栏palette不见了,如何把它找出来? NO.3: 如何建立与数据库的关联? NO.4: 域和数据项 ...

  8. 深入理解Java内存模型(三)——顺序一致性

    数据竞争与顺序一致性保证 当程序未正确同步时,就会存在数据竞争.java内存模型规范对数据竞争的定义如下: 在一个线程中写一个变量, 在另一个线程读同一个变量, 而且写和读没有通过同步来排序. 当代码 ...

  9. Linux内核的整体架构

    Linux内核的整体架构 作者:蜗蜗 发布于:2014-2-21 13:23 分类:Linux内核分析 原文:http://www.wowotech.net/linux_kenrel/11.html ...

  10. hdu 5067 Harry And Dig Machine (状态压缩dp)

    题目链接 bc上的一道题,刚开始想用这个方法做的,因为刚刚做了一个类似的题,但是想到这只是bc的第二题, 以为用bfs水一下就过去了,结果MLE了,因为bfs的队列里的状态太多了,耗内存太厉害. 题意 ...