//修改按钮
procedure TForm1.Button3Click(Sender: TObject);
begin
if not AddrBook.SetRecord(nCurRec, memo1.Text) then
ShowMessage(“error”);
end;

    好,下面我就举一个详细的例子来说明,如何将界面代码和功能代码分离。
   
假设我要做一个简单的个人通讯录管理软件,很显然,整个软件分为两部分:一部分是面象用户的,也就是所谓界面部分,我可以提供四个按钮(分别为“添加”、“删除”、“修改”、“查找”)和一个编辑框(显示通讯录信息和接受用户输入)用于和用户交互;另一部分是功能化的,也就是软件内部的对于通讯录的存取操作。
    于是,有了一个TAddrBook类,它是对功能化部分的抽象。
    TAddrBook = class
    private
        //一些私有成员
    public
        constructor Create;
        destructor Destroy;override;
        GetCount: Integer;
        FindRecord(strString): Integer;
        GetRecord(nIndex:Integer): String;
        SetRecord(nIndex:integer; strRec:String): Boolean;
        AddRecord(strRec:String): Boolean;
        DelRecord(nIndex): Boolean;
        //其它共有成员函数
    end;
    私有成员之所以无法确定,主要是取决于这个类的实现。
   
   
如此,可以将对通讯录的存取操作的逻辑封装。而界面部分的代码不会涉及到这些存取逻辑。界面部分代码如下:
    var
      Form1: TForm1;
      AddrBook: TAddrBook;
      nCurRec: Integer;

Delphi中的关键字与保留字

分类整理 Delphi 中的“关键字”和“保留字”,方便查询

感谢原作者的收集整理!

 

关键字和保留字的区别在于,关键字不推荐作标示符(编译器已经内置相关函数或者留给保留实现),二保留字是根本不可能作标示符(编译时有警示!)

【系统保留字】

and            array          as             asm
begin          case           class          const
constructor    destructor     dispinterface  div
do             downto         else           end
except         exports        file           finalization
finally        for            function       goto
if             implementation in             inherited
initialization inline         interface      is
label          library        mod            nil
not            object         of             or
out            packed         procedure      program
property       raise          record         repeat
resourcestring set            shl            shr
string         then           threadvar      to
try            type           unit           until
uses           var            while          with
xor

【系统关键字】

absolute       abstract       assembler      automated
cdecl          contains       default        dispid
dynamic        export         external       far
forward        implements     index          message
name           near           nodefault      on
overload       override       package        pascal
private        protected      public         published
read           readonly       register       reintroduce
requires       resident       safecall       stdcall
stored         virtual        write          writeonly

{——————————————————————————-
  名称:【program】、【library】、【package】、【unit】

  功能:用于标识程序文件、动态链接库文件、包文件、单元文件的文件头。

        program :编译后生成 exe 文件,可以直接执行。

        library :编译后生成 dll 文件,可被其他程序调用。

        package :编译后生成 bpl 文件,可被安装到 delphi
的控件库中,从而在以后
        的开发中使用控件。

        unit :编译后生成 dcu 文件,将被编译到 exe 和 dll 文件中。
——————————————————————————-}

{ 空程序文件 Test.dpr }
program Project1;
begin
end.


{ 空动态链接库文件 Test.dpr }
library Project1;
begin
end.


{ 空包文件 Test.dpk }
package Package1;
end.


{ 空单元文件 Test.pas }
unit Unit1;
interface
implementation
end.

{——————————————————————————-
  名称:【contains】、【requires】

  功能:与包文件相关的关键字。

        contains :用于指出某个包(package)是否包含某个文件,用
contains 引入
        的文件必须被添加到包文件中,它可以避免关键文件的引用丢失。

        requires :指出编译 package 时的必备条件。若 requires
的条件未满足,则
        不允许编译包。
——————————————————————————-}

package MyPackage;
requires
  { 包需要运行在下面的环境中 }
  rtl, clx;
contains
  { 包需要用到下面的文件 }
  DB, DBMyControl;
end.

{——————————————————————————-
 
名称:【interface】、【implementation】、【initialization】、【finalization】

  功能:与单元文件相关的关键字。

        interface :单元文件的接口部分,也用于定义接口类型。

        implementation :单元文件的实现部分。

        initialization :单元文件的初始化部分。

        finalization :单元文件的反初始化部分。
——————————————————————————-}

{ 单元文件结构 }
unit Unit1;
interface
  { 引用其他单元、定义数据类型、定义过程函数、定义变量常量等 }
  { 此处定义的类型或数据对其他单元是可见的(可访问的) }
implementation
  { 引用其他单元、实现接口部分定义的类型、过程、函数的具体代码 }
  { 此处定义的类型或变量只对本单元可见 }
initialization
  { 这里编写单元被载入时所要调用的方法 }
  { 通常是初始化一些不能自动初始化的对象,也可以不用 }
  { initialization 最常用的情况是对 OLE 对象做初始化 }
finalization
  { 这里编写单元被释放时所要调用的方法 }
  { 通常是释放掉单元中不能自动释放的对象,也可以不用 }
  { finalization 最常用的情况是对 OLE 对象做反初始化 }
end.


{ 定义接口类型 }
IEnumerator = interface(IInterface)
  function GetCurrent: TObject;
  function MoveNext: Boolean;
  procedure Reset;
  property Current: TObject read GetCurrent;
end;

{——————————————————————————-
  名称:【uses】

  功能:用于引用一个外部的单元。
        uses 语句通常放在一个单元的接口部分或实现部分。
——————————————————————————-}

{ 程序文件 }
program Project1;
uses
  Forms,
  Unit1 in ‘Unit1.pas’ {Form1};
begin
end.


{ 单元文件 }
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes;
implementation
uses
  StrUtrls;
end.

{——————————————————————————-
  名称:【type】

  功能:用于声明各种类型。
——————————————————————————-}

type

  { 声明接口 }
  IMyInterface = interface
  end;

  { 声明类指针 }
  PMyObject = ^TMyObject;
  { 声明类 }
  TMyObject = class(TObject)
  end;

  { 声明结构 }
  TMyRecord = record
  end;

  { 声明函数 }
  TMyFunc = function(I: Integer): string;

  { 声明自定义类型 }
  TCol = (cItemA, cItemB, cItemC);
  TColSet = set of TCol;
  TLatter = ‘A’ .. ‘Z’;
  TInt = Integer;

{——————————————————————————-
 
名称:【var】、【const】、【resourcestring】、【threadvar】、【absolute】

  功能:用于声明变量和常量
        var :声明变量,或者声明函数的参数为传址参数。

        const :声明常量,或者声明函数的参数为常量参数。

        resourcestring :声明资源字符串。

        threadvar
:声明一个线程内变量,此变量仅供各个线程内部使用。如果在线程外
       
初始化该变量,则初始化的内容不会被传入线程内,当线程创建时,该变量为空,
       
且被认为是线程内的私有变量,与线程外的该变量互不干扰,与其它线程内的该变
        量也互不干扰。threadvar
必须声明为全局变量,然后在各个线程内使用。
        Delphi 说在线程内使用的 threadvar
必须在线程结束前手动释放其占用的空间。
        比如 S := ”; 即将字符串资源释放。关于资源释放,Delphi
没有更多解释。

        absolute :定义一个变量与另一个变量地址相同
——————————————————————————-}

{ 关于变量和常量的声明 }

procedure TForm1.Button1Click(Sender: TObject);
resourcestring
  { 声明资源字符串 }
  rsButtonCaption = ‘测试(&T)’;
const
  { 声明常量 }
  conMax = 50;
var
  { 声明变量 }
  iNum: Integer;
  bFlag: Boolean;
begin
  Button1.Caption := rsButtonCaption;

  iNum := Random(100);
  bFlag := iNum >= conMax;
  Caption := IntToStr(iNum) + ‘ – ‘ + BoolToStr(bFlag, True);
end;


{ 关于 threadvar }

unit Form1Unit;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R   *.DFM}

{ NOTE: 将 GlobalStr 的定义由 var 改为 threadvar 来观察不同 }
var { 线程内外共用此变量 }
// threadvar  { 线程内将创建此变量的一个副本,线程内外此变量互不干扰 }
  GlobalStr: string;

type
  TTLSThread = class(TThread)
  private
    FNewStr: String;
  protected
    procedure Execute; override;
  public
    constructor Create; overload;
    constructor Create(const ANewStr: String); overload;
  end;

procedure SetShowStr(const S: String; const sTitle: string = ”);
begin
  if S = ” then
    MessageBox(0, PChar(GlobalStr), PChar(sTitle), MB_OK)
  else
    GlobalStr := S;
end;

constructor TTLSThread.Create;
begin
  inherited Create(False);
end;

constructor TTLSThread.Create(const ANewStr: String);
begin
  FNewStr := ANewStr;
  inherited Create(False);
end;

procedure TTLSThread.Execute;
begin
  FreeOnTerminate := True;
  SetShowStr(FNewStr);
  SetShowStr(”, ‘线程内 – 线程执行时’);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetShowStr(‘线程外的 GlobalStr 变量’);
  SetShowStr(”, ‘线程外 – 线程创建前’);

  TTLSThread.Create(‘线程内的 GlobalStr 若为 threadvar
类型,则与线程外的 GlobalStr 无关’);
  Sleep(100);

  SetShowStr(”, ‘线程外 – 线程创建后,观察 GlobalStr
在线程内外是否不同’);
end;

end.


{ 同地址变量 }

{ 下面的代码声明了变量 ucLen 的起始地址与 ShortStrig 型变量 sStr
相同,由
  于 ShortString 的第 0 个位置保存了字符串的长度,所以 ucLen
的值即为字符
  串的长度。 }

procedure TForm1.Button1Click(Sender: TObject);
var
  sStr:  ShortString;
  ucLen: Byte absolute sStr;
begin
  sStr := ‘1234567890’;
  Caption := IntToStr(ucLen);
end;

{——————————————————————————-
  名称:【begin】、【end】

  功能:begin end :组合使用,可以表示一段代码或一个程序的开始和结束。

        end 还可以与 case, class, interface, asm, unit, package
等相匹配。

        对于语句块,end 后必须添加分号。而对于单元或包,end
后必须添加句点。
在 If 语句中 else 关键字前的 end 后不允许添加分号。
——————————————————————————-}

{ 一段代码的开始和结束 }

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  I := Random(100);
  if I < 50 then
  begin
    Caption := IntToStr(I);
  end
  else
  begin
    Caption := IntToStr(I – 50);
  end;
end;


{ 程序文件的开始和结束 }

program Project1;
begin
end.


{ 包文件的开始和结束,不需要 begin }

package Package1;
end.


{ 类的开始和结束,不需要 begin }

TMyObject = class(TObject)
end;

{——————————————————————————-
  名称:【if】、【then】、【else】、【case】

  功能:if then else 组合使用,构成条件判断语句,当不需要 else
时,可以省略 else
        ,当 else 与 if 配合使用时,else
前面的一条语句不能以分号结束。

        case else 组合使用,构成条件选择语句。

        else 还可以与 try except on 语句组合,构成异常处理语句,详见
except。
——————————————————————————-}

{ if then else(条件判断) }

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  I := Random(100);
  if I < 50 then
    Caption := IntToStr(I)
  else
    Caption := IntToStr(I – 50);
  end;
end;

{ if then(条件判断,无 else) }

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  I := Random(100);
  if I < 50 then
    Caption := IntToStr(I);
end;


{ case else(条件选择) }

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  I := Random(100);
  case I of
    1 .. 33:
      Caption := ‘小’;
    34 .. 66:
      Caption := ‘中’;
    67 .. 99:
      Caption := ‘大’;
  else
    Caption := ‘0’;
  end;
end;

{——————————————————————————-
 
名称:【for】、【to】、【downto】、【do】、【while】、【repeat】、【until】

  功能:for to(或downto) do 组合使用,构成 for 循环语句。

        while do 组合,构成 while 循环语句。

        repeat until 组合,构成 repeat 循环语句。

        for 还可以与 in 组合,构成 for 循环语句,详见 in
        do 还可以与 with 组合构成默认对象语句,详见 with
        do 还可以与 try except on 组合使用,构成异常处理语句,详见
except。
——————————————————————————-}

{ for 循环语句,循环变量递增 }

procedure TForm1.Button1Click(Sender: TObject);
var
  I, iSum: Integer;
begin
  iSum := 0;
  for I := 1 to 100 do
    iSum := iSum + I;
  Caption := IntToStr(iSum);  { 结果 5050 }
end;

{ for 循环语句,循环变量递减 }

procedure TForm1.Button1Click(Sender: TObject);
var
  I, iSum: Integer;
begin
  iSum := 0;
  for I := 100 downto 1 do
    iSum := iSum + I;
  Caption := IntToStr(iSum);  { 结果 5050 }
end;


{ while 语句 }

procedure TForm1.Button1Click(Sender: TObject);
var
  I, iSum: Integer;
begin
  iSum := 0;
  I := 0;
  while I <= 100 do begin
    iSum := iSum + I;
    Inc(I);
  end;
  Caption := IntToStr(iSum);  { 结果 5050 }
end;


{ repeat 语句 }

procedure TForm1.Button1Click(Sender: TObject);
var
  I, iSum: Integer;
begin
  iSum := 0;
  I := 0;
  repeat
    iSum := iSum + I;
    Inc(I);
  until I > 100;
  Caption := IntToStr(iSum);  { 结果 5050 }
end;

{——————————————————————————-
  名称:【with】

  功能:用于设置默认对象,简化代码。
——————————————————————————-}

{ with 语句 }

procedure TForm1.Button1Click(Sender: TObject);
begin

// 这里的 4 行代码可以用 with 语句简化输入:
// (Sender as TButton).Left := 0;
// (Sender as TButton).Top := 0;
// (Sender as TButton).Width := 120;
// (Sender as TButton).Height := 60;

  with (Sender as TButton) do
  begin
    Left := 0;
    Top := 0;
    Width := 120;
    Height := 60;
  end;

  Caption := ‘测试 with 语句’;
  Width := Width div 2;
  Height := Height div 2;
end;

{——————————————————————————-
  名称:【label】、【goto】

  功能:goto  :无条件跳转
        label :定义跳转标签,goto 语句只能跳转到已定义的标签位置。
——————————————————————————-}

procedure TForm1.Button1Click(Sender: TObject);
label
  AA;
var
  I, iNum: Integer;
begin
  I := 0;
  iNum := 0;
AA:
  inc(I);
  iNum := iNum + I;
  if I < 10 then
    goto AA;

  Caption := IntToStr(iNum);  { 结果 55 }
end;

{——————————————————————————-
  名称:【asm】、【assembler】

  功能:asm 用于在程序中插入汇编代码。
        使用汇编代码时, 必须使用 asm …end; 的结构,而非 begin …
end;

        assembler 用于支持早期的汇编, 如80386等。它和 asm 的区别是 asm
允许使用
        Win32 汇编, 而 assembler 只允许 80×86 汇编, 它不允许 Invoke
语句的出现。
——————————————————————————-}

function IntToHex(Value: Integer; Digits: Integer): string;
asm
  CMP  EDX, 32
  JBE  @A1
  xor  EDX, EDX
@A1: PUSH ESI
  MOV  ESI, ESP
  SUB  ESP, 32
  PUSH ECX
  MOV  ECX, 16
  CALL CvtInt
  MOV  EDX, ESI
  POP  EAX
  CALL System.@LStrFromPCharLen
  ADD  ESP, 32
  POP  ESI
end;

{——————————————————————————-
 
名称:【and】、【or】、【not】、【xor】、【shl】、【shr】、【div】、【mod】

  功能:Delphi 运算符。

        and(逻辑与 或 按位与) or(逻辑或 或 按位或) not(逻辑非 或
按位否)
        xor(逻辑异或 或 按位异或) shl(位左移) shr(位右移)
        div(整除) mod(求余数)

        xor(逻辑异或 或 按位异或)我喜欢把它叫做“逻辑异”,只要 xor
两边的布尔
        值不相同(相异),结果就为 True,否则就为 False。只要 xor
两边的位状态不
        同(0 和 1 不同),结果就为 1,否则就为 0。
——————————————————————————-}

{ 逻辑与 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B: Integer;
begin
  A := 1;
  B := -1;
  if (A > 0) and (B > 0) then
    Caption := ‘True’
  else
    Caption := ‘False’;   { 结果 False }
end;

{ 逻辑或 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B: Integer;
begin
  A := 1;
  B := -1;
  if (A > 0) or (B > 0) then
    Caption := ‘True’   { 结果 True }
  else
    Caption := ‘False’;
end;

{ 逻辑非 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B: Integer;
begin
  A := 1;
  B := -1;
  if not A > B then
    Caption := ‘True’
  else
    Caption := ‘False’;   { 结果 False }
end;

{ 逻辑异或 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B: Integer;
begin
  A := 1;
  B := -1;
  if (A > 0) xor (B > 0) then
    Caption := ‘True’  { xor 两边的布尔值不同,结果 True }
  else
    Caption := ‘False’;
end;


{ 按位与 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B, C: Integer;
begin
  A := 360;
  B := 120;
  C := A and B;
  Caption := IntToStr(C);  { 结果:104 }
end;

{ 按位或 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B, C: Integer;
begin
  A := 360;
  B := 120;
  C := A or B;
  Caption := IntToStr(C);  { 结果:376 }
end;

{ 按位否 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, C: Integer;
begin
  A := 360;
  C := not A;
  Caption := IntToStr(C);  { 结果:-361 }
end;

{ 按位异或 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B, C: Integer;
begin
  A := 360;
  B := 120;
  C := A xor B;
  Caption := IntToStr(C);  { 结果:272 }
end;

{ 位左移 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, C: Integer;
begin
  A := 360;
  C := A shl 1;  { 相当于 A 乘以 2 的 1 次方 }
  Caption := IntToStr(C);  { 结果:720 }
end;

{ 位右移 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, C: Integer;
begin
  A := 360;
  C := A shr 1;  { 相当于 A 除以 2 的 1 次方 }
  Caption := IntToStr(C);  { 结果:180 }
end;


{ 整除 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B, C: Integer;
begin
  A := 36;
  B := 5;
  C := A div B;
  Caption := IntToStr(C);  { 结果:7 }
end;

{ 求余数 }

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B, C: Integer;
begin
  A := 36;
  B := 5;
  C := A mod B;
  Caption := IntToStr(C);  { 结果:1 }
end;

{——————————————————————————-
  名称:【try】、【finally】、【except】、【on】、【raise】

  功能:这些都是异常处理语句。

        try finally 组合使用,构成异常处理语句。先执行 try
部分的语句,无论 try
        部分是否执行成功,finally 部分都会被执行。

        try except on 组合使用,构成异常处理语句。正常情况下执行 try
部分的语句。
        如果发生异常,则执行 except 后的语句。

        raise
用于抛出异常。如果希望通过外部程序处理异常,或是在异常发生时重新将
        异常抛出,可以使用 raise 语句。异常被抛出后,raise
后面的代码将不被执行。
——————————————————————————-}

{ try finally(异常处理) }

procedure TForm1.Button1Click(Sender: TObject);
var
  Strs: TStringList;
begin
  Strs := TStringList.Create;
  try
    Strs.Add(‘finally Test’);
    Caption := Strs[0];
  finally
    Strs.Free;
  end;
end;


{ try except on else(异常处理) }

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  S: String;
begin
  S := ‘123A’;
  try
    I := StrToInt(S);
  except
    on EZeroDivide do
      Caption := ‘EZeroDivide’;
    on EOverflow do
      Caption := ‘EOverflow’;
    else
      Caption := ‘Unknow Error’;
  end;
end;


{ raise 抛出异常 }

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  { 普通代码中抛出异常 }
  I := -1;
  if I < 0 then
    raise exception.Create(‘整数不能小于 0’);
  ShowMessage(‘异常被抛出后…’);
end;

{ raise 抛出异常 }

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  S: string;
begin
  { try except 中抛出异常 }
  try
    S := ‘123A’;
    I := StrToInt(S);
  except
    on E: exception do
      raise exception.Create(E.Message);
  end;
  ShowMessage(‘异常被抛出后…’);
end;

{——————————————————————————-
  名称:【procedure】、【function】、【forward】、【out】

  功能:Delphi 函数、过程相关关键字。

        procedure
:定义过程,过程无返回值。主要用来执行一系列动作。还可以用来声
        明自定义函数类型。

        function
:定义函数,函数有返回值。主要用来计算某一结果。还可以用来声明
        自定义函数类型。

        forward
:用于函数(或过程)的前置声明,这样可以使代码中“较先实现的函数
        ”可
以调用“较后实现的函数”,如果“较后实现的函数”不做前置声明,则它不
        能被前面的函数调用。

        out :定义函数(或过程)的参数为传出类型,out
类型的参数用来将函数的执行
       
结果通过此参数返回给调用者(传地参数)。调用者在调用函数时,不需要给
out
        类型的参数赋值,赋了也没用。

        还有之前提到的一个关键字 var
:定义函数(或过程)的参数为传址类型,var
       
类型的参数在函数内的一切改变都会返回给调用者,调用者也可以在调用函数前,
        给 var 参数赋值,然后传递到函数里面使用。
——————————————————————————-}

{ 函数前置声明 }
function CalcPerimeter(R: Double): Double; forward;
function CalcArea(R: Double): Double; forward;

{ 过程:执行一系列动作,显示圆的半径、周长、面积信息 }
procedure ShowInfo(Radius: Double);
var
  sRadius: string;
  sPerimeter: string;
  sArea: string;
begin
  sRadius := FloatToStr(Radius);

  { 如果不做前置声明,则这里无法调用 CalcPerimeter }
  sPerimeter := FloatToStr(CalcPerimeter(Radius));

  { 如果不做前置声明,则这里无法调用 CalcArea }
  sArea := FloatToStr(CalcArea(Radius));

  ShowMessage(‘半径:’ + sRadius + #13#10 +
  ‘周长:’ +  sPerimeter + #13#10 +
  ‘面积:’ + sArea);
end;

{ 函数:计算圆的周长 }
function CalcPerimeter(R: Double): Double;
begin
  { 2 乘以 派 乘以 半径,Pi 是系统函数,计算圆周率 }
  Result := 2 * Pi * R;
end;

{ 函数:计算圆的面积 }
function CalcArea(R: Double): Double;
begin
  { 派 乘以 半径的平方,Pi 是系统函数,计算圆周率 }
  Result := Pi * R * R;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowInfo(10.5);
  ShowInfo(30.25);
end;


{ 声明自定义函数类型 TMyFunc }
type
  TMyFunc = function(I: Integer): Integer;

{ 某个函数 }
function GetCountNum(Num: Integer): Integer;
var
  I: Integer;
begin
  Result := 0;
  for I := 0 to Num do
  begin
    Result := Result + I;
  end;
end;

{ 这里只是简单测试,自定义函数类型一般用作函数或过程的参数 }
procedure TForm1.Button1Click(Sender: TObject);
var
  MyFunc: TMyFunc;
  iCountNum: Integer;
begin
  { 将某个同类型的函数赋值给 MyFunc }
  MyFunc := GetCountNum;

  { 然后 MyFunc 就可以像普通函数一样使用了 }
  iCountNum := MyFunc(100);

  Caption := IntToStr(iCountNum);  { 结果 5050 }
end;


{ var 和 out 测试 }

{ 过程是没有返回值的,但是我们可以通过 var 或 out 参数来返回数据 }
procedure Test(var I: Integer; out S: String);
begin
  { 先看看传进来的是什么 }
  ShowMessage(‘参数I:’ + IntToStr(I) + #13#10 + ‘参数S:’ + S);  { S
将为空 }
  { 修改参数的值,看能否传递到过程外面去 }
  I := I + 100;
  S := S + ‘AfterStr’;  { 如果我们将这一行代码注释掉,则 S
将返回空字符串 }
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  A: Integer;
  B: String;
begin
  A := 1;
  B := ‘ABC’;
  Test(A, B);  { ‘ABC’ 无法传入到函数中 }
  Caption := IntToStr(A ) + ‘ ‘ + B;    { 结果 101 AfterStr }
end;

{——————————————————————————-
  名称:【cdecl】、【pascal】、【stdcall】、【safecall】、【register】
        【varargs】

 
功能:函数(或过程)的调用协定,各个调用协定的要求内容太多,这里只是简单说明,
        具体可以翻查相关资料。

        cdecl :规定了从 C 或 C++ 编写的 DLL
中调用函数所必须遵守的规则。它可以
        将 C 或 C++ 中的数据类型转换为 Delphi 的类型。

        pascal
:规定参数从左向右传递。函数调用时要对所有的变量进行初始化,避免
        因异步线程调用而产生的错误,保留它是为了向下兼容。

        stdcall :规定参数从右向左传递。同时 stdcall 规定,
被调函数是大小写敏感
       
的。在调用函数时,如果函数名中有一个字符的大小写出错,则该函数将调用失败。

        safecall :规定被 COM
调用的函数所必须遵守的规则。在编译时,safecall 声
        明的函数被编译成与 COM 接口兼容的。

        register :Delphi
专用的函数调用协定,直接通过寄存器传递参数,因此传递速
        度非常块。
        register 关键字也被用来注册控件。

varargs :标示了引用参数,它必须和 cdecl
关键字联用,表明允许调用的函数
使用引用传递。
——————————————————————————-}

{ cdecl }

// { 例如 C++ 中的代码 }
// int CFun(int i)
// {
//   return i*2;
// }

{ 如果这个函数被编译在 Test.dll 中, 则用 Delphi 调用时必须使用如下方式
}
function CFun(i: Integer): Integer; Cdecl; external ‘Test.dll’;


{ pascal }

function Test(I, J, K, L: Integer): Integer; pascal;
begin
  Result := I * J * K * L;
end;


{ stdcall }

Library Test;

function Func1(I, J, K, L: Integer): Integer; stdcall;
begin
  Result := I * J * K * L;
end;

exports
  Func1;

begin
end.

{ 主调方函数声明 }
function Func1(I, J, K, L: Integer):
Integer; stdcall; external ‘Test.dll’;


{ safecall }

{ 编译时,声明函数的调用协定为 safecall 类型 }
procedure MyFunc(S: WideString); safecall;

{ 编译后函数成为与 COM 接口兼容的类型 }
procedure MyFunc(S: PAnsiString);


{ register }

function Func1(I, J, K, L: Integer): Integer; register;
begin
  Result := I * J * K * L;
end;


{ 注册控件 }

procedure Register;
begin
  RegisterComponents(‘Sample’, [TTest]);
end;


{ varargs }

{ 这段代码从 C++ 的类库中引用了 Printf 函数,并允许按引用的方式传入参数
}
function printf(Format: PChar): Integer; cdecl; varargs;

{——————————————————————————-
  名称:【class】

  功能:定义类类型,或声明一个类方法。

        具体参见 Delphi 相关资料。
——————————————————————————-}

{ 定义空类,默认继承自 TObject }
type
  TMyObject = class
  end;


{ 定义 TMyObject 类并测试类方法 }
type
  TMyObject = class(TObject)
  private
    FName: string;
  protected
  public
    { 定义类方法,类方法可以直接通过类调用 }
    class procedure ShowResult;
  published
    property Name: string read FName write FName;
  end;

{ 实现类方法 }
class procedure TMyObject.ShowResult;
begin
  ShowMessage(‘调用成功!’);
end;

{ 调用类方法 }
procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyObject.ShowResult;  { 直接通过 TMyClass 调用,不用创建实例 }
end;

{——————————————————————————-
  名称:【record】、【packed】

  功能:record :定义结构类型。

       
一个结构体可以视为一个不需要实例化的类(某些地方和对象用法不同)。
        具体参见 Delphi 相关资料。

        packed
:用于对结构类型对象或数组类型对象进行打包,打包后的对象体积能显著
        减小。打包后元素对齐位置也会发生变化,不再对齐到与 CPU
处理能力相匹配的位
        置,因此打包后的对象,处理速度会降低。详细信息请查阅相关资料。
——————————————————————————-}

{ 定义 record 类型 }
type
  TMyRec = record
    Name: string;
    Age: Cardinal;
    Sex: Boolean;
  end;


{ 定义 record 类型,用法类似于 class }
type
  TMyRec = record
  private
    FName: string;
  public
    procedure ShowResult;
    property Name: string read FName write FName;
  end;

{ 实现 record 方法 }
procedure TMyRec.ShowResult;
begin
  ShowMessage(‘调用成功!’);
end;

{ 调用 record 方法 }
procedure TForm1.Button1Click(Sender: TObject);
var
  MyRec: TMyRec;
begin
  MyRec.Name := ‘Record 测试’;
  ShowMessage(MyRec.Name);
  MyRec.ShowResult;
end;


{ 打包 }

type
  { 未打包 }
  TMyRecA = record
    Name: string;
    Age: Byte;
    Sex: Boolean;
  end;

  { 打包 }
  TMyRecB = packed record
    Name: string;
    Age: Byte;
    Sex: Boolean;
  end;

  { 未打包 }
  TMyArrayA = array [0 .. 32] of Byte;

  { 打包 }
  TMyArrayB = packed array [0 .. 32] of Byte;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(SizeOf(TMyRecA)));
  ShowMessage(IntToStr(SizeOf(TMyRecB)));
  ShowMessage(IntToStr(SizeOf(TMyArrayA)));
  ShowMessage(IntToStr(SizeOf(TMyArrayB)));
end;

{——————————————————————————-
  名称:【object】

  功能:定义对象类型,或声明“对象函数”或“对象过程”。

        定义对象类型是 Object Pascal
中的一个古老的功能,这个功能现在已经被
        class 取代。具体参见 Delphi 相关资料。
——————————————————————————-}

{ 定义对象 }
type
  MyObject = object
  private
    FName: string;
  protected
  public
    procedure ShowResult;
    property Name: string read FName write FName;
  end;

  { 实现对象方法 }
procedure MyObject.ShowResult;
begin
  ShowMessage(‘调用成功!’);
end;

{ 调用对象方法 }
procedure TForm1.Button1Click(Sender: TObject);
var
   MyObj :MyObject;
begin
  MyObj.Name := ‘Object 测试’;
  ShowMessage(MyObj.Name);
  MyObj.ShowResult;
end;


type
  { 该函数不能是独立的函数,必须是某个对象的成员 of Object }
  TMyFun = function(I: Integer): Integer of object;
  { 该过程不能是独立的过程,必须是某个对象的成员 of Object }
  TMyProc = procedure(S: string) of object;

{——————————————————————————-
 
名称:【automated】、【private】、【protected】、【public】、【published】

  功能:定义类(或结构、对象)成员的可访问类型。

        automated :自动成员,它能够使程序的版本向下兼容。
        ComObj 单元内的成员及其实例不能使用 automated 访问区分符。
        不能用于结构类型和对象类型。

        private :私有成员,只有类所在单元可以访问。

        protected :保护成员,只有子类可以访问,不能用于结构类型。

        public :公开成员,可以在任何地方被访问。

        published
:发布成员,可以在运行时被访问,不能用于结构类型和对象类型。
——————————————————————————-}

type
  TMyObject = class
  automated
    { 这里放置自动类型的成员 }
  private
    { 这里放置私有类型的成员 }
  protected
    { 这里放置保护类型的成员 }
  public
    { 这里放置公开类型的成员 }
  published
    { 这里放置发布类型的成员 }
  end;


{ 关于 automated }
type
  TMyObject = class
  automated
    Str:WideString;
  end;

{ 如果在程序的下一个版本中, 将 Str 修改成 }

type
  TMyObject = class
  automated
    Str: AnsiString;
  end;

{ 则新版本的 Str 变量能够接受旧版本的 WideString 型数据,并自动转换成
AnsiString。
  在实际开发中,如果没有特殊的需要,一般不用 automated 访问区分符。}

{——————————————————————————-
  名称:【constructor】、【destructor】、【property】

  功能:定义类类型或对象类型的构造函数,析构函数和属性。

        constructor
:声明或定义一个构造函数,可以用于类类型、对象类型、结构类型。
        结构类型不允许定义无参数的构造函数。

        destructor
:声明或定义一个析构函数,可以用于类类型、对象类型。
        析构函数主要用来释放对象资源。析构函数只允许覆盖,不允许重载。

        property
:声明或定义一个属性,可以用于类类型、对象类型、结构类型。
        属性分为显式属性和隐式属性两种,只有声明为 published
访问类型的属性才是
        显式属性,才可以直接在对象查看器中查看。
        事件也是属性的一种,可以在 published 下用 property 进行声明。
——————————————————————————-}

{ 定义类类型 }
type
  TMyObj = class(TObject)
  private
    FName: string;
    FAge: Cardinal;
    FOnTexChange: TEvent;  { 事件 }
  protected
  public
    { 构造函数 }
    constructor Create;
{ 析构函数 }
destructor Destroy; override;
  published
    { 发布属性 }
    property Name: string read FName write FName;
    property Age: Cardinal read FAge write FAge;
    { 发布事件 }
    property OnTextChange:
TEvent read FOnTexChange write FOnTexChange;
  end;


{ 定义结构类型 }
type
  MyRec = record
  private
    FName: string;
    FAge: Cardinal;
  public
    { 构造函数 }
    constructor Create(Name: string);
{ 不能有析构函数 }
{ 公开属性 }
    property Age: Cardinal read FAge write FAge;
  end;


{ 定义对象类型 }
type
  MyObj = object
  private
    FName: string;
    FAge: Cardinal;
  protected
  public
    { 构造函数 }
    constructor Create;
{ 析构函数 }
destructor Destroy; override;
{ 公开属性 }
    property Name: string read FName write FName;
    property Age: Cardinal read FAge write FAge;
  end;

{——————————————————————————-
  名称:【read】、【write】、【default】、【nodefault】
        【readonly】、【writeonly】、【stored】、【message】

  功能:定义属性的各种参数

        read :用于标识属性读取时所使用的成员或方法。

        write :用于标识属性写入时所使用的成员或方法。

        default :指示属性的默认值,或指示一个属性为类的默认属性。
        只有有序类型的属性才允许默认值的存在,
否则必须在构造函数中初始化属性值。

        nodefault :指示一个属性不允许有默认值,这通常用在继承中。

        readonly :指示一个属性为只读。
        当 readonly 设为 True 时, 不允许用户修改属性,
只能通过其他对象来操作

        writeonly :指示一个属性为只写。
        当 writeonly 设为 true
时,不允许用户读取属性,只能通过其他对象来操作

        stored
:指示一个属性的值是否能被保留,若指定了True,则允许对属性值进行
        赋值撤销的操作。

        message :用于声明消息方法。
        带有 message
的方法必须指出接收的消息类型,并通过引用将消息传入方法中,
        以便进行处理。
        用户可以自定义消息,自定义消息也能够被 message
接收,并引发事件。
——————————————————————————-}

{ 属性的读取 }
type
  TMyObject = class(TObject)
  private
    FValue: Integer;
  published
    { 表明 Value 属性从 FValue 成员上读出值 }
    property Value: Integer read FValue;
  end;


{ 属性的写入 }
type
  TMyObject = class(TObject)
  private
    FValue: Integer;
  published
    { 表明 Value 属性的值写入到 FValue 成员上 }
    property Value: Integer write FValue;
  end;


{ 默认值和默认属性 }
type
  TMyObject = class(TObject)
  private
    FAuto: Boolean;
    FCount: Integer;
    FNameList: TStrings;
  public
    constructor Create;
    { 属性默认值 default True、 default 0 }
    property Auto: Boolean read FAuto write FAuto default True;
    property Count: Integer read FCount write FCount default 0;
    { 默认属性 default }
    property Names[Index: Integer]: TStrings read FNameList
      write FNameList default;
  end;

constructor TMyObject.Create;
begin
  inherited;
  { 分配对象资源 }
  FNameList := TStrings.Create;
  { 设置属性默认值 }
  FAuto := True;
end;


{ 去掉默认值 }
type
  TMyObjA = class
  private
    FValue: Integer;
  published
    property Value: Integer read FValue write FValue default 0;
  end;

  TMyObjB = class(TMyObjA)
  published
    property Value: Integer read FValue write FValue nodefault;
  end;

{ 由上例可知, TMyObjA 中的 Value 有默认值 0,TMyObjB 继承了
TMyObjA,所以也继承
  了其默认值, 在此用 NoDefault 去掉默认值。 }


{ 只读属性 }
property ReadOnly;


{ 只写属性 }
property WriteOnly;


{ 保留属性值 }
type
  TComponent = class
  private
    FName: TComponentName;
  published
    property Name:
TComponentName read FName write SetName stored False;
  end;


{ 声明消息方法 }

unit Form1Unit;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure Refresh(var Msg: TMessage); message WM_SIZE;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ 此方法捕捉窗口尺寸被改变的消息 }
procedure TForm1.Refresh(var Msg: TMessage);
begin
  { 先将窗口的尺寸显示在标题栏中 }
  Caption := IntToStr(Width) + ‘ – ‘ +  IntToStr(Height);
  { 再调用默认消息处理函数,重绘窗口 }
  inherited;
end;

{ 随机调整窗口的大小 }
procedure TForm1.Button1Click(Sender: TObject);
var
  Size: Integer;
begin
  { 先将按钮自身移到窗口左上角,以免窗口缩小后被遮挡 }
  (Sender as TButton).Left := 0;
  (Sender as TButton).Top := 0;

  { 获取一个随机数,可正可负 }
  Randomize;
  Size := Random(100) – 50;
  { 设置窗口的新大小 }
  Width := Width + Size;
  Height := Height + Size;
  { 当窗口大小改变后,就会触发 WM_SIZE 消息,从而调用我们定义的
TForm1.Refresh }
end;

end.

{——————————————————————————-
  名称:【array】、【file】、【set】、【string】

  功能:定义各种数据类型,或声明各种数据类型的变量。

        array :声明一个数组。

        file :声明一个文件类型。

        set :声明一个集合。

        string :声明一个字符串。
——————————————————————————-}

{ 定义各种数据类型 }
type
  TMyArray = array[0..9] of string; { 声明静态数组 }
  TCharArray = array of Char; { 声明动态数组 }
  TButtonFile = file of TButton;  { 声明 TButton 格式的文件类型 }
  TIntFile = file of Integer; { 声明 Integer 格式的文件类型 }
  TLatterSet = set of ‘A’..’Z’;  { 声明大写字母集合 }
  TByteSet = set of byte;  { 声明字节集合 }
  TName = string[32];  { 声明 32 个自己长度的 ShortString 类型 }

procedure TForm1.Button1Click(Sender: TObject);
var
  { 声明各种数据类型的变量 }
  MyArray1: TMyArray;
  MyArray2: array of Char;
  MyFile1: TButtonFile;
  MyFile2: file of Integer;
  MySet1: TLatterSet;
  MySet2: set of ‘A’..’Z’;
  Name1: TName;
  Name2: string[255];
  Name3: string;

  I: Integer;
begin
  { 数组类型测试 }
  SetLength(MyArray2, 26);
  for I := Low(MyArray2) to High(MyArray2) do
    MyArray2[I] := Chr(65 + I);
  ShowMessage(string(MyArray2));

  { 集合类型测试 }
  MySet1 := [‘A’..’Z’];
  MySet2 := MySet1;
  if ‘A’ in MySet1 then ShowMessage(‘Found A in MySet1’);
  if CharInSet(‘A’, MySet2) then ShowMessage(‘Found A in MySet2’);
end;

{——————————————————————————-
  名称:【in】

  功能:用于判断一个集合中是否包含某个元素。

        也可以被用在 for 语句中,用于循环取出一个集合中的元素。

        也用于工程文件中,用于标识某个文件是否被工程所引用。
——————————————————————————-}

procedure TForm1.Button1Click(Sender: TObject);
var
  Item: Char;
  MySet: set of ‘A’..’Z’;
begin
  { 初始化集合 }
  MySet := [‘A’..’Z’];

  { in 用于集合 }
  if ‘A’ in MySet then ShowMessage(‘A is in MySet’);

  { in 用于 for 语句 }
  for Item in MySet do
    Caption := Caption + Item;
end;

{ in 用于工程文件 }
program Project1;
uses
  Forms,
  Unit1 in ‘Unit1.pas’ {Form1};
begin
end.

{——————————————————————————-
  名称:【nil】

  功能:指示一个指针(某些对象其实也是指针)为空。
——————————————————————————-}

{ 检测控件是否存在 }
procedure TForm1.Button1Click(Sender: TObject);
var
  MyEdit: TEdit;
begin
  { 仅仅释放 }
  MyEdit := TEdit.Create(Self);
  try
    MyEdit.Parent := Self;
    MyEdit.Show;
    Caption := BoolToStr(Assigned(MyEdit), True);
  finally
    MyEdit.Free;
  end;
  ShowMessage(‘控件是否存在:’ + BoolToStr(Assigned(MyEdit), True));

  { 释放并 nil }
  MyEdit := TEdit.Create(Self);
  try
    MyEdit.Parent := Self;
    MyEdit.Show;
    Caption := BoolToStr(Assigned(MyEdit), True);
  finally
    MyEdit.Free;
    MyEdit := nil; { 这里的两行代码一般合起来写为 FreeAndNil(MyEdit) }
  end;
  ShowMessage(‘控件是否存在:’ + BoolToStr(Assigned(MyEdit), True));
end;

{——————————————————————————-
  名称:【virtual】、【dynamic】、【abstract】、【inline】、【static】

  功能:指示一个类方法的类型。

        virtual
:虚拟方法可以被子类覆写,虚拟方法可以加快调用速度,但浪费内存。

        dynamic
:动态方法可以被子类覆写,动态方法可以节省内存,但调用速度没有虚
        拟方法快。

        abstract :抽象方法可以被子类覆写,abstract 关键字必须与 virtual

        dynamic 关键字同时使用。

       
包含“抽象方法”的类称为“抽象类”。抽象类可以被实例化,但实例化的对象不
        能调用抽象方法,否则会抛出异常。

        inline
:定义内联函数或内联汇编代码,内联函数类似于宏,编译器在编译程序
       
时,会将内联函数的代码直接搬到调用者的代码里面去,作为调用者的一部分,也
       
就不存在调用内联函数的说法了,直接就是一行行代码。内联函数一般是体积较小
       
且被频繁调用的函数。内联函数可以提高代码的执行效率。如果没有定义内联函数
       
,则编译器会自己判断将那些函数作为内联函数处理,以便提高程序的执行效率,
       
所以一般情况下我们不需要手动指定内联函数。内联说明对于编译器来说只是一种
       
建议,编译器可以忽略这个建议,如果我们指定了内联函数而编译器觉得不合适,
        那么编译器可以拒绝将指定的函数内联。
        内联函数不是纯粹的函数,因此不能递归调用。
——————————————————————————-}

{ 虚拟方法 }
TObject = class
public
  procedure Dispatch(var Message); virtual;
  destructor Destroy; virtual;
end;


{ 动态方法 }
TCustomForm = class
protected
  procedure DoHide; dynamic;
  procedure DoShow; dynamic;
end;


{ TStrings 中的抽象方法 }
TStrings = class
protected
  { 这里只需要定义,具体功能靠子类去实现 }
  function Get(Index: Integer): string; virtual; abstract;
  { 这里只需要定义,具体功能靠子类去实现 }
  function GetCount: Integer; virtual; abstract;
end;


{ 测试抽象方法 Delphi XE2 }
type

  { 定义一个抽象方法 }
  TMyObject = class(TObject)
  public
    procedure Test1;
    procedure Test2; virtual; abstract;
  end;

procedure TMyObject.Test1;
begin
  ShowMessage(‘Test1 OK’);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyObj: TMyObject;
begin
  MyObj := TMyObject.Create;
  try
    MyObj.Test1;
    MyObj.Test2;
    { 此处调用了抽象方法 MyObj.Test,运行时将会抛出异常 }
    { 后面的代码将不被执行 }
    Caption := ‘测试抽象方法’;
  finally
    MyObj.Free;
  end;
end;


{ 内联函数 }
function Test(S: string): string; inline;
begin
  Result := ‘显示结果:’ + S;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Caption := Test(Caption);
  { 此处调用了内联函数,所以,在编译时,此处的代码就被改成了
    Caption := ‘显示结果:’ + Caption;
    直接将内联函数的代码搬过来进行编译 }
end;

{——————————————————————————-
  名称:【override】、【overload】、【reintroduce】、【inherited】

  功能:override :指示子类覆写父类的一个 virtual 或 dynamic
方法。覆盖时必须沿
        用被覆盖方法的声明,并且不允许修改原方法的参数和返回类型。

        overload
:指示重载一个同名函数、过程或方法。重载的同名方法时,必须具备
       
“参数、类型或顺序不同”的条件。调用重载方法时,根据输入的参数不同来调用
        不同的重载方法。

        reintroduce
:指示重新发布父类的方法。如果要覆盖的方法是静态方法,或是需
        要修改方法的参数等,必须用 reintroduce 进行重发布。对于 virtual

        dynamic 方法,可以直接用 override 进行覆盖。

        inherited :调用父类的方法。
——————————————————————————-}

{ 覆写父类的方法 }
type

{ 父类定义三个方法,其中两个可以被覆写,一个抽象方法 }
TMyObjectA = class(TObject)
protected
  procedure Test1; virtual;
public
  function Test2: string; dynamic; abstract;
  function Test3: Integer;
end;

{ 子类继承父类的三个,同时将其中两个改写 }
TMyObjectB = class(TMyObjectA)
protected
  procedure Test1; override;
public
  function Test2: string; override;
end;

{ 父类 – 方法1}
procedure TMyObjectA.Test1;
begin
  ShowMessage(‘A’);
end;

{ 父类 – 方法2 }
{ 抽象方法只定义,不实现 }

{ 父类 – 方法3 }
function TMyObjectA.Test3: Integer;
begin
  Result := 1;
end;

{ 子类 – 重写方法1 }
procedure TMyObjectB.Test1;
begin
  ShowMessage(‘B’);
end;

{ 子类 – 重写方法2 }
function TMyObjectB.Test2: string;
begin
  Result := ‘B’;
end;

{ 调用各个方法 }
procedure TForm1.Button1Click(Sender: TObject);
var
  MyObjB: TMyObjectB;
begin
  { 测试子类 }
  MyObjB := TMyObjectB.Create;
  try
    MyObjB.Test1;
    Caption := MyObjB.Test2 + IntToStr(MyObjB.Test3);
  finally
    MyObjB.Free;
  end;
end;


{ 重载函数 }

function ShowInfo(Info: Boolean): string; overload;
begin
  ShowMessage(BoolToStr(Info, True));
end;

function ShowInfo(Info: Integer): string; overload;
begin
  ShowMessage(IntToStr(Info));
end;

function ShowInfo(Info: string): string; overload;
begin
  ShowMessage(Info);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowInfo(‘你好吗?’);
  ShowInfo(123);
  ShowInfo(True);
end;


{ 重新发布父类的方法 }

type
  { 父类 }
  TMyObjectA = class
    procedure Test;
  end;

  { 子类 }
  TMyObjectB = class(TMyObjectA)
    procedure Test; reintroduce;
  end;

  { 孙类 }
  TMyObjectC = class(TMyObjectB)
    procedure Test(I: Integer); reintroduce;
  end;


{ 调用父类方法 }

type
  { 父类 }
  TMyObjectA = class(TObject)
  public
    procedure Test1; virtual;
    procedure Test2; virtual;
  end;

  { 子类 }
  TMyObjectB = class(TMyObjectA)
  public
    procedure Test1; override;
  end;

{ 父类 – 虚拟方法1 }
procedure TMyObjectA.Test1;
begin
  ShowMessage(‘父类方法 1’);
end;

{ 父类 – 虚拟方法2 }
procedure TMyObjectA.Test2;
begin
  ShowMessage(‘父类方法 2’);
end;

{ 子类 – 覆写父类方法1 }
procedure TMyObjectB.Test1;
begin
  { 调用父类方法中的同名方法,即 Test1 }
  inherited;
  { 调用父类方法中的 Test2 }
  inherited Test2;
  ShowMessage(‘子类方法 1’);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyObjB: TMyObjectB;
begin
  MyObjB := TMyObjectB.Create;
  try
    MyObjB.Test1;
  finally
    MyObjB.Free;
  end;
end;

{——————————————————————————-
  名称:【of】、【as】、【is】

  功能:of :用于和其他关键字构成指定的结构。
        of可以与 case, class, array, file, set, object 连用。

        as :用于将一个类对象当作另一种类型使用。

        is :用于判断对象是否属于某一类型。
——————————————————————————-}

{ of 关键字 }

type
  TMyClass = class of TEdit;
  TMyFun = function(I: Integer): Integer of Object;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyArr    : array of Integer;
  MyFile   : file of Byte;
  MySet    : set of ‘A’ .. ‘Z’;
  MyClass  : TMyClass;
  MyFunc   : TMyFun;
begin
  case Self.Tag of
    0:
      Caption := ‘Tag Zero’;
  else
    Caption := ‘Tag No Zero’;
  end;
end;


{ as 关键字 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  { Sender 本来是 TObject 类型,现在当作 TButton 类型使用 }
  (Sender as TButton).Caption := ‘测试 as’
end;


{ is 关键字 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  { 显然 Sender 与 TForm 无关 }
  if Sender is TForm then ShowMessage(‘Sender is TForm’);

  { Sender 就是 TButton }
  if Sender is TButton then ShowMessage(‘Sender is TButton’);
  { Sender 继承自 TCustomButton }
  if Sender is TCustomButton then ShowMessage(‘Sender is
TCustomButton’);
  { Sender 继承自 TObject }
  if Sender is TObject then ShowMessage(‘Sender is TObject’);
end;

{——————————————————————————-
  名称:【implements】

  功能:implements
:指出了一个属性从接口继承,此时属性被转换成接口对象。通过接口
        动态绑定属性,并动态的设定属性值。

        还有之前提到的一个关键字 Interface:用于声明一个接口类型。
——————————————————————————-}

{ implements }

type
  IMyInterface = interface
    procedure P1;
    procedure P2;
  end;

  TMyImplclass = class
    procedure P1;
    procedure P2;
  end;

  TMyclass = class(TInterfacedObject, IMyInterface)
    FMyImplClass: TMyImplclass;
    property MyImplClass: TMyImplclass read FMyImplClass
      implements IMyInterface;
    procedure IMyInterface.P1 = MyP1;
    procedure MyP1;
  end;

  // 通过implements声明后, 可以在类声明时指出接口中方法的实体,
如上例中的:
  // procedure IMyInterface.P1 = MyP1;


{ Interface 接口类型声明 }

type
  IMalloc = interface(IInterface)
  [‘{00000002-0000-0000-C000-000000000046}’]
    function Alloc(Size: Integer): Pointer; stdcall;
    function Realloc(P: Pointer; Size: Integer): Pointer; stdcall;
    procedure Free(P: Pointer); stdcall;
    function GetSize(P: Pointer): Integer; stdcall;
    function DidAlloc(P: Pointer): Integer; stdcall;
    procedure HeapMinimize; stdcall;
  end;

{——————————————————————————-
  名称:【index】、【near】、【far】、【export】、【exports】
        【external】、【name】、【resident】

  功能:index
:用于在属性中标识序号,以便用相同的属性方法(Get,Set)对不同的属
        性进行操作。index 关键字也用于在属性中指出多个元素。

near :标明函数的调用协定,指出函数可以被本地调用。其他程序可以用 dll

        形式调用程序内的函数,保留它是为了向下兼容。

        far :标明了函数调用协定,指出函数可以被远程调用。其他程序可以用
dll 的
        形式调用程序内的函数,保留它是为了向下兼容。

export
:明函数的调用协定,指出函数可以被输出,输出的函数能被本地或远程
        调用。其他程序可以用 dll
的形式调用程序内的函数,保留它是为了向下兼容。

        exports
:用于输出对象,它必须被用在接口和实现之间,可以同时输出多个项,
        项与项之间用逗号分开。

        external :用于引用一个外部的或是 OBJ 内的方法。使用 external
关键字时,
        代码必须注意大小写,否则将出现错误。

name :用于指出方法的别名,对于一个要被外部引用的方法,建议用 name
申请
       
方法别名,以避免外部程序改动方法的实体内容。从外部引用一个方法时,如果该
        方法有别名,则必须用 name 进行标识。

        resident :使用 resident,则当 DLLs
装入时,特定的输出信息始终保持在内
        存中。这样当其它应用程序调用该过程时,可以比利用名字扫描 DLL
入口降低时
        间开销。对于那些其它应用程序常常要调用的过程或函数,使用
resident 指示是
        合适的。这个关键字已经被废弃不用了。
——————————————————————————-}

{ index:属性序号 }

type
  TMyObject = class(TObject)
  private
    FLeft: Integer;
    FTop: Integer;
    FWidth: Integer;
    FHeight: Integer;
    function GetInfo(const Index: Integer): Longint;
    procedure SetInfo(const Index: Integer; const Value: Longint);
  public
    property iLeft: Longint index 0 read GetInfo write SetInfo;
    property iTop: Longint index 1 read GetInfo write SetInfo;
    property iWidth: Longint index 2 read GetInfo write SetInfo;
    property iHeight: Longint index 3 read GetInfo write SetInfo;
  end;

function TMyObject.GetInfo(const Index: Integer): Longint;
begin
  case Index of
    0:
      Result := FLeft;
    1:
      Result := FTop;
    2:
      Result := FWidth;
    3:
      Result :=FHeight;
  end;
end;

procedure TMyObject.SetInfo(const Index: Integer; const Value:
Longint);
begin
  case Index of
    0:
      FLeft := Value;
    1:
      FTop := Value;
    2:
      FWidth := Value;
    3:
      FHeight :=Value;
  end;
end;


{ index:属性的多个元素 }

type
  TMyObject = class(TObject)
  private
    FList: TStringList;
    function GetItem(Index: Integer): string;
    procedure SetItem(Index: Integer; const Value: string);
  public
    constructor Create;
    destructor Destroy; override;
    property Items[Index:
Integer]: string read GetItem write SetItem;
  end;

constructor TMyObject.Create;
begin
  inherited;
  FList := TStringList.Create;
  FList.Add(‘星期一’);
  FList.Add(‘星期二’);
  FList.Add(‘星期三’);
  FList.Add(‘星期四’);
  FList.Add(‘星期五’);
  FList.Add(‘星期六’);
  FList.Add(‘星期日’);
end;

destructor TMyObject.Destroy;
begin
  FList.Free;
  inherited;
end;

function TMyObject.GetItem(Index: Integer): string;
begin

  if (Index >= 0) and (Index <= (FList.Count – 1)) then
    Result := FList[Index]
  else
    Result := ‘Out of Index’;
end;

procedure TMyObject.SetItem(Index: Integer; const Value: string);
begin
  if (Index >= 0) and (Index <= (FList.Count – 1)) then
    FList[Index] := Value;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  MyObj: TMyObject;
begin
  MyObj := TMyObject.Create;
  try
    Caption := MyObj.Items[2];
    MyObj.Items[2] := ‘Wednesday’;
    for I := 0 to 6 do
      ShowMessage(MyObj.Items[I]);
  finally
    MyObj.Free;
  end;
end;


{ near }

function Add(A, B: Integer): Integer; near;
{ 如果这个程序被编译为
Test.exe,并且另一个处于本地的程序需要调用这个函数,可以
  使用以下语句 }
function Add(A, B: Integer): Integer; stdcall; external ‘Test.exe’;


{ far }

function Add(a,b: Integer): Integer; far;
{ 如果这个程序被编译为 Test.exe,
并且另一个处于其他计算机的程序需要调用这个函
  数, 可以使用以下语句 }
function Add(a,b: Integer): Integer; stdcall; external ‘Test.exe’;


{ export }

function Add(a,b: Integer): Integer; export;
{ 如果这个程序被编译为 Test.exe,
而另一个程序需要调用这个函数,可以使用以下语句 }
function Add(a,b: Integer): Integer; stdcall; external ‘Test.exe’;


{ exports }

library Test;

function TestFunc(I: Integer): string; stdcall;
begin
  Result := IntToStr(I);
end;

exports TestFunc;

begin

end.

{ 如果输出的对象被重载,则必须给对象起个别名,并注明参数 }

library Test;

function TestFunc(I: Integer): string; overload; stdcall;
begin
  Result := IntToStr(I); 
end;

function TestFunc(S: string): Integer; overload; stdcall;
begin
  Result := StrToInt(S);
end;

exports
  TestFunc(I: Integer) name ‘TestFunc1’,
  TestFunc(S: string)  name ‘TestFunc2’;

begin

end.


{ external }

{$L Test.OBJ}
procedure TestFunc(I:Integer); external;

{ 如果是从 dll 或外部程序中引用,则可以使用以下代码 }
function TestFunc(FileName: string): string; external ‘Test.dll’;

{ 如果被引用的函数被重载,则必须另外指出引用的名称 }
function MyFunc1(Code:
Integer): string; overload; stdcall; external ‘Test.dll’ name ‘TestFunc1’;
function MyFunc2(Name: string):
Integer; overload; stdcall; external ‘Test.dll’ name ‘TestFunc2’;


{ name }

function MessageBox(HWnd: Integer; Text, Caption: PChar; Flags:
Integer)
  : Integer; stdcall; external ‘user32.dll’ name ‘MessageBoxA’;


{ resident }

function Test: string;
exports Test name ‘MyTest’ resident;
编译时会给出警告:Symbol ‘RESIDENT’ is deprecated

{——————————————————————————-
  名称:【dispinterface】、【dispid】

  功能:Microsoft 专用。

        dispinterface :用于声明一个特定的适配器接口,
这个适配器能够接受标准系统
        接口中传入传出的数据。用 DispInterface
声明的接口不能被继承,只能够被引
        用。DispInterface 方法只能调用,并且必须被动态绑定。可以通过
DispId 为接
        口内方法分配适配序号。DispInterface 仅能用于 Windows 平台,
如果在 Linux
        下进行开发, 则此关键字会自动被系统屏蔽。

        dispid :DispInterface 接口中,用于指定特定的适配序号。在
DispInterface
        接口中, 适配序号必须是唯一的。如果不指定
DispId,则系统会自动分配适配序号
        给接口内每一个方法,可以通过适配序号访问 DispInterface
接口中的方法。
——————————————————————————-}

{ dispinterface }

{ 通常情况下,不使用 DispInterface }


{ dispid }

type
  IStringsDisp = dispinterface
    [‘{EE05DFE2-5549-11D0-9EA9-0020AF3D82DA}’]
    property ControlDefault[Index: Integer]:
Olevariant dispid 0; default;
    function Count: Integer; dispid 1;
    property Item[Index: Integer]: Olevariant dispid 2;
    procedure Remove(Index: Integer); dispid 3;
    procedure Clear; dispid 4;
    function Add(Item: Olevariant): Integer; dispid 5;
    function _NewEnum: IUnknown; dispid – 4;
  end;

implementation

东日文档

    procedure TForm1.FormClose(Sender: TObject; var Action:
TCloseAction);
    begin
        AddrBook.Free;
    end;
   
    //添加按钮
    procedure TForm1.Button1Click(Sender: TObject);
    begin
        if not AddrBook.AddRecord(memo1.Text) then
            ShowMessage(“error”);
    end;
   
    //删除按钮
    procedure TForm1.Button2Click(Sender: TObject);
    begin
        if not AddrBook.DelRecord(nCurRec) then
            ShowMessage(“error”);
    end;
   
    //修改按钮
    procedure TForm1.Button3Click(Sender: TObject);
    begin
        if not AddrBook.SetRecord(nCurRec, memo1.Text) then
            ShowMessage(“error”);
    end;
   
    //查找按钮
    procedure TForm1.Button4Click(Sender: TObject);
    begin
        memo1.Text :=
AddrBook.GetRecord(AddrBook.FindRecord(memo1.Text));
    end;
   
   
以上界面部分的代码,不涉及任何存取逻辑,每个模块的代码简单,易懂,便于维护。而实际上,该通讯录是使用数据库保存还是用文本文件来保存,界面代码都不知道;使用数据库的话,是通过ODBC还是ADO还是BDE访问数据库,界面代码也不知道。实际上,这些存取逻辑的东西取决于TAddrBook类的实现,TAddrBook类的实现可以单独的放在一个.pas文件中,对TAddrBook类的实现的任何更改,都不会影响界面部分。维护代码的时候,将更改局限于某一个模块中的做法是非常明智的。
   
   
Nicrosoft([email protected])
于 2001.7.14

好,下面就举一个详细的例子来说明,如何将界面代码和功能代码分离。
假设要做一个简单的个人通讯录管理软件,很显然,整个软件分为两部分:一部分是面象用户的,也就是所谓界面部分,我可以提供四个按钮(分别为“添加”、“删除”、“修改”、“查找”)和一个编辑框(显示通讯录信息和接受用户输入)用于和用户交互;另一部分是功能化的,也就是软件内部的对于通讯录的存取操作。
于是,有了一个TAddrBook类,它是对功能化部分的抽象。

   
很多朋友看了上次我写的“创建良好设计的代码(基于Delphi/VCL)”后,对我说感觉上可以接受其中的观点,但似乎说得太简单,不够具体;也有的朋友对其中的一个小例子有些异议。因此便有了此文。

//删除按钮
procedure TForm1.Button2Click(Sender: TObject);
begin
if not AddrBook.DelRecord(nCurRec) then
ShowMessage(“error”);
end;

    implementation   
   
    procedure TForm1.FormCreate(Sender: TObject);
    begin
        AddrBook := TAddrBook.Create;
        nCurRec := AddrBook.GetCount;
    end;

的确,单纯从这三行代码来看,似乎有了“滥用对象”之嫌。也许是例子过于简单,给人的感觉是TObjectXXX只有GetStringList这一个public成员函数,如果真的这样的话,那可真是“滥用对象”了。类是对对象的抽象,而对象是由状态和操作(也就是数据和对数据的操作)的集合组成。因此,没有状态的对象不是对象!没有私有数据成员的类的设计是失败的设计(那不是类,而是接口了)。

    上次,我举的例子是这样的:假设要从某处获得一个字符串列表,然后显示于
TListBox 中,我所推崇的代码是:
    ObjectXXX := TObjectXXX.Create;
    ListBox1.Items := ObjectXXX.GetStringList;
    ObjectXXX.Free;
   
的确,我承认,单纯从这三行代码来看,似乎有了“滥用对象”之嫌。也许是例子过于简单,给人的感觉是TObjectXXX只有GetStringList这一个public成员函数,如果真的这样的话,那可真是“滥用对象”了。类是对对象的抽象,而对象是由状态和操作(也就是数据和对数据的操作)的集合组成。因此,没有状态的对象不是对象!没有私有数据成员的类的设计是失败的设计(那不是类,而是接口了)。

Author

发表评论

电子邮件地址不会被公开。 必填项已用*标注