Delphi语法(六)接口

第七章 接口

type
  接口名称 = Interface(父接口的名称)//一般是没有的
  [GUID]//Ctrl+Alt+G自动生成,是唯一的,如果相同,则表示这两个接口完全一致
    //成员列表
  end;

注:Interface不能声明为局部类型;

GUID虽然可以省略,但是建议不要省略;

接口的成员只能是方法和属性,属性也只能通过方法读写;

接口中没必要也不允许指定任何访问权限;

声明属性时不能指定stored,default,nodefault,但数组属性可以指定default;

不存在接口类型的对象所以接口中不能含有构造和析构函数;

接口不能实例化,其中的方法不存在动态或静态绑定,所以方法后不能加关键词:

virtual,dynamic,abstract,override;

一个类可以继承多个接口,逗号隔开;

类继承接口时,父类名称不能省略,要写在第一位;

类继承一个接口就要实现这个接口所有的方法和属性;

接口实现举例

type
  I1 = Interface
    procedure F1;
  end;
  I2 = Interface
    procedure F2;
  end;
  T2 = class(TObject, I1, I2)
    procedure F1;
    procedure F2;
  end;

所有接口继承自根接口IInterface,其中最基本的方法由类TInterfacedObject实现,在System.pas;

TInterfacedObject = class(TObject, IInterface)
...
end;

当我们调用接口时,可以继承这个类而非TObject作为父类,可以省掉基本方法的实现;

实现接口中的属性举例

type
  I1 = Interface
    procedure SetX(value: Integer);
    function GetX: Integer;
    property P1: Integer read GetX write SetX;
  end;
  T1 = class(TInterfacedObject, I1);
    strict private
      I: Integer;
      procedure SetX(value: Integer);
      function GetX: Integer;
    published
      property P1: Integer read GetX write SetX;
    end;
  function T1.GetX: Integer;
  begin
    Result := self.I;
  end;
  procedure T1.SetX(value: Integer);
  begin
    Self.I := value;
  end;
  var
    obj: T1;
  begin
    obj := T1.Create;
    obj.P1 := 78;
    Writeln(obj.P1);
    FreeAndNil(obj);
    Readln;
  end.

I用于存储P1的值;

在子类中改变父类中实现的接口举例

  type
    I1 = Interface
      procedure F1;
    T1 = class(TInterfacedObject, I1);
      procedure F1;
    end;

T1的派生类T2需要以一种不同的方式来重载实现I1,只需要让T2继承I1即可;

  T2 = class(T1, I1)
    procedure F1;
  end;
  
  procedure T1.F1;
  begin
    Writeln('T1.F1');
  end;
  
  procedure T2.F1;
  begin
    Writeln('T2.F1');
  end;
  
  var
    Interface1: I1;
  begin
    Interface1 := T1.Create;
    Interface1.F1;
    Interface1 := T2.Create;
    Interface1.F1;
  end.

注:T2中的I1接口完全隐藏了T1中的I1接口,如果在T1中给I1接口的方法声明了别名,在T2中将失效;

7.4方法别名

主要是解决方法名称相同的问题;

举例

type
  I1 = Interface
    procedure SetX(value: Integer);
    function GetX: Integer;
    property P1: Integer read GetX write SetX;
  end;
  I2 = Interface
    procedure SetX(value: Integer);
    function GetX: Integer;
    property P2: Integer read GetX write SetX;
  end;
  T1 = class(TInterfacedObject, I1, I2)
  strict private
    I, J: Integer;
    procedure I1.SetX = set1;            //other name
    procedure I1.GetX = get1;
    procedure I2.SetX = set2;
    procedure I2.GetX = get2; 
  public
    procedure Set1(value: Integer);      //change
    function Get1: Integer;
    procedure Set2(value: Integer);
    function Get2: Integer;
    property p1: Integer read Get1 write Set1; //change
    property p2: Integer read Get2 write Set2; 
  end;

别名只是方法的另一个名字,并不能改变方法除了名字之外的任何信息;

7.5接口的代理

如果在T1中继承I1接口,而T0中已经实现了I1接口,可以通过以下方式直接使用

type
  I1 = Interface
    procedure F1;
  end;
  T0 = class(TInterfacedObject, I1)
    procedure F1;
  end;
  T1 = class(TInterfacedObject, I1)
  strict private
    FInterface: T1;
  public 
    property P1: I1 read FInterface write FInterface Implements I1;
  end;
procedure T0.F1;
begin
  Writeln('this is T0.F1');
end.
var
  Interface1: I1;
  obj: T1;
begin
  obj := T1.Create;
  obj.P1 := T0.Create;
  Interface1 := obj;
  Interface1.F1;
  Readln;
end.

步骤:

1.在类中声明接口类型的属性;

2.把其他实现了接口的对象赋给这个属性;

3.通过属性中存储的对象调用这个接口的功能;

以上是通过接口作为属性的类型,还可以使用类类型的属性;

T1 = class(TInterfacedObject, I1)
  strict private
    FInterface: T0;  //change
  public
    //change
    property P1: T0 read FInterface write FInterface Implements I1;
end;
procedure T0.F1;
begin
  Writeln('T0.F1');
end;
var
  Interface1: I1;
  obj: T1;
begin
  obj := T1.Create;
  obj.P1 := T0.Create;
  Interface1 := obj;
  Interface1.F1;
  Readln;
end.

这种方式成为对象代理;

7.6接口的赋值和转型

非接口变量中只有变体变量可以接受接口类型的值;

变体变量第三章;

将一个IDispatch类型的接口值赋给变体变量时,变体变量的类型码的值是varDispatch;

其他任何接口值赋给变体变量时,类型码均为varUnknown;

非接口变量值赋给接口变量:变体变量值赋给接口变量,nil赋给接口,类的对象赋给接口;

当变体变量的类型码是varUnknown时,它可以当成值赋给IInterface(IUnknown)类型的变量;

类型码是varDispatch或varEmpty时,既可以赋给IInterface(IUnknown)类型的接口变量,也可以赋给IDispatch类型的接口变量;

其他任何类型都不能赋给接口类型,任何类型也不能接口变体值;

nil可以作为值赋给任何接口类型的变量;

如果将对象赋给某个接口类型的变量,则此对象必须实现了此接口本身,即使是实现了此接口的子代接口也不行;

举例

type
  I1 = Interface(IInterface)
  End;
  I2 = Interface(I1)
  End;
  T1 = class(TInterfacedObject, I2)
  end;
var
  obj: T1;
  Interface1: I1;
  Interface2: I2;
begin
  obj := T1.Create;
  Interface1 := obj;
  //that is wrong
  Interface2 := obj;
  FreeAndNil(obj);
end.

obj实现了I2接口,它不能作为值赋给I2之外的任何接口类型的变量;

派生的接口值赋给祖先接口变量;

也只有这种情况可以将接口变量值赋给接口变量;

不过这基本没有什么意义,举例

type
  I1 = Interface
    procedure M1;
  end;
  I2 = Interface(I1)
    procedure M2;
  end;
  T1 = class(TInterfacedObject, I2)
    procedure M1;
    procedure M2;
  end;
var
  obj: T1;
  Interface1: I1;
  Interface2: I2;
begin
  obj := T1.Create;
  Interface2 := obj;
  Interface2.M2;
  Interface1 := Interface2;//here
  Interface1.M1;
  Readln;
end.

这里相当于

Interface1 := obj;

type
  I1 = Interface
  end;
  T1 = class(TInterfacedObject, I1)
  end;
var
  obj: T1;
  Interface1: I1;

然后可以

Interface1 := obj;
obj := T1(Interface1);

这种转换是一种隐匿转换,某些时候不能确保安全性;

应当使用as操作符;

举例

type
  T1 = Interface
  ['{D8C36ABA-FCF9-46F1-A55B-8E69EEA75244}']
    procedure M1;
  end;
  T1 = class(TInterfacedObject, I1)
    procedure M1;
    procedure M2;
    procedure M3;virtual;
  end;
  
procedure T1.M1;
begin
  Writeln('T1.M1');
end;

procedure T1.M2;
begin
  Writeln('T1.M2');
end;

procedure T1.M3;
begin
  Writeln('T1.M3');
end;
var
  Interface1: T1;
  obj: T1;
begin
  obj := T1.Create;
  Interface1 := obj as T1;
  Interface1.M1;
  Readln;
end.

注:使用as转型必须加上GUID,否则无法编译;

begin
  obj := T1.Create;
  Interface1 := obj as T1;
  // three more code
  obj := nil;
  obj := Interface1 as T1;
  obj.M3;
  //end more
  Interface1.M1;
  Readln;
end.

首先将obj设置成nil,将Interface1转为T1类型的引用赋给obj,调用M3;

注意到M3是虚方法,这就解除了M3和obj之间的静态绑定;

还记得静态绑定吗

接口的生存期受系统自动管理,无需手动销毁;

通过接口实现多态举例

unit Unit3;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm3 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  IGreed = Interface
    procedure Greed;
  End;
  TCHGreen = class(TInterfacedObject, IGreed)
    procedure Greed;
  end;
  TJPGreen = class(TInterfacedObject, IGreed)
    procedure Greed;
  end;
  TENGreen = class(TInterfacedObject, IGreed)
    procedure Greed;
  end;
var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TCHGreen.Greed;
begin
  ShowMessage('zao');
end;

procedure TJPGreen.Greed;
begin
  ShowMessage('shang');
end;

procedure TENGreen.Greed;
begin
  ShowMessage('hao');
end;

procedure TForm3.Button1Click(Sender: TObject);
var
  obj: IGreed;
begin
  obj := TCHGreen.Create;
  obj.Greed;
end;

procedure TForm3.Button2Click(Sender: TObject);
var
  obj: IGreed;
begin
  obj := TJPGreen.Create;
  obj.Greed;
end;

procedure TForm3.Button3Click(Sender: TObject);
var
  obj: IGreed;
begin
  obj := TENGreen.Create;
  obj.Greed;
end;

end.

这里各个类没有继承TGreed而是实现了IGreed接口;

调用方法通过接口调用;

所有的对象都无需手动销毁;

由于接口的生存周期由系统自动管理,所以它指向的实体也会由系统自动销毁,无需手动销毁。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Delphi是一种广泛使用的编程语言,具有强大的集成开发环境(IDE),可以用于开发各种软件应用程序。在使用Delphi调用SAP(Systems, Applications, and Products in Data Processing)接口函数的过程中,我们首先需要创建一个SAP连接,然后使用该连接来调用我们所需的接口函数。 首先,我们需要确保已经安装了相应的SAP RFC(Remote Function Call)库,并在Delphi中导入相关的扩展包。然后,我们需要通过创建一个RFC连接对象来建立与SAP系统的通信。在连接对象中,我们需要提供SAP系统的相关信息,比如SAP服务器的主机名、系统编号、客户端号码等。 一旦我们成功建立了与SAP系统的连接,我们就可以开始调用SAP接口函数了。我们可以使用RFC连接对象的CallFunction方法来调用函数,在调用时需要提供接口函数的名称以及相应的参数。在调用成功后,我们可以通过获取返回的结果数据来处理和使用。 在调用SAP接口函数时,我们需要确保提供正确的函数参数和参数类型,以及正确的数据格式。我们可以使用Delphi提供的相关功能来进行参数类型转换和数据格式处理。 在调用函数之前,我们还需要考虑如何处理和处理潜在的错误和异常。我们可以使用Delphi提供的异常处理机制来捕获和处理可能出现的错误,以确保程序的稳定性和可靠性。 综上所述,使用Delphi调用SAP接口函数需要先建立与SAP系统的连接,然后通过RFC连接对象调用相应的接口函数,并处理返回的结果数据和潜在的错误和异常。这样可以实现Delphi与SAP系统的集成,实现数据的交互和共享。 ### 回答2: Delphi是一种编程语言,可以用于调用SAP的接口函数。SAP是一种集成的企业资源计划软件,它提供了各种接口函数,可以与其他系统进行数据交换和集成。 在Delphi中调用SAP接口函数,首先需要通过SAP提供的API文档了解接口函数的参数和返回值。然后,在Delphi中创建一个新的项目或使用现有的项目,在项目中引入SAP的相关库文件和命名空间。 接下来,可以使用Delphi的相关语法,如函数调用、变量声明等,来调用SAP的接口函数。根据接口函数的参数要求,可以在Delphi代码中传入需要的参数,并接收返回值。 在调用SAP接口函数时,需要确保Delphi和SAP的连接是正常的。可以通过设置连接参数,如SAP系统的用户名、密码、连接字符串等来确保连接成功。 在调用SAP接口函数之前,可能需要进行一些前期准备工作。例如,可能需要创建SAP连接对象、打开连接、连接到具体的SAP系统等。 调用SAP接口函数后,可以根据返回值来进行相应的处理。根据接口函数的返回值类型,可以使用条件语句、循环语句等来判断并处理返回结果。 在调用SAP接口函数时,还需要注意异常处理。如果在调用过程中发生了错误或异常,可以使用Delphi提供的异常处理机制来捕获和处理异常,以防止程序崩溃或不稳定。 总之,通过Delphi调用SAP接口函数可以实现与SAP系统的数据交换和集成。这样可以方便地在Delphi程序中使用SAP的功能和数据,提高系统的灵活性和扩展性。 ### 回答3: 使用Delphi调用SAP接口函数需要以下步骤: 1. 在Delphi中设置与SAP接口通信的环境。这可以通过使用SAP提供的相关库文件来完成。通常,这些库文件可以作为一个包被导入到Delphi项目中。 2. 使用SAP提供的函数或类来建立与SAP服务器的连接。这些函数或类可以通过指定SAP服务器的IP地址、端口号、用户名和密码来建立连接。 3. 一旦连接建立,可以通过调用相应的SAP函数或方法来执行所需的操作。这些操作可能包括读取或写入SAP系统的数据,调用SAP的业务逻辑函数或者执行其他与SAP相关的任务。 4. 在调用SAP函数或方法之前,可能需要根据SAP接口的要求设置相应的输入参数。这些参数通常是一个结构体或一个数组,其中包含了传递给SAP函数的数据。 5. 当SAP函数执行完成后,可能会返回一个结果,这可以是一个结构体或一个值。根据需要,可以解析结果并进一步处理。 6. 最后,使用SAP提供的功能来关闭与SAP服务器的连接,并释放相关的资源,以确保程序的完整性和安全性。 需要注意的是,具体的调用方式和步骤可能因为SAP接口的版本和特性而有所不同。因此,在进行Delphi调用SAP接口函数的实际操作前,应该先详细阅读SAP的相关文档,并了解其具体的接口规范和要求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值