在
Delphi
中,一个正在开发的应用程序可以被称作项目或者工程。一般地,一个项目主要由
dpr
(项目)、
pas
(单元)和
dfm
(窗体)三种文件组成,另外还有一些附属文件,如
res
(资源)文件等。其中项目文件可以被看做是一种特殊的单元。在源代码中,项目文件用关键字
program
标识,单元文件用
unit
标识。
通常,一个项目只有惟一的
dpr
文件。一个
dfm
文件总是有对应的
pas
文件,但是
pas
文件可以没有对应的
pas
文件。
如果打开
Delphi
,选择菜单
File|New|Application
,则可以新建一个项目。该项目包括一个项目文件—
—
Project1.dpr
、一个窗体文件—
—
Unit1.dfm
和一个对应的单元文件—
—
Unit1.pas
。选择菜单
Project|View Source
可以看到项目文件的内容;在窗体上单击右键,从弹出的菜单中选择
View as Text
可以看到窗体文件的内容。
这些文件的内容都必须按照一定的组织结构来编写,编译器按照既定的组织结构来识别这些内容并进行编译。在本节里,我们讨论
program
和
unit
两种单元文件的组织结构。
Program
的组织结构
一个项目文件被关键字
program
标识,因此,在这里我将项目文件的源代码称作
program
。以下是一个简单的
program
:
program
Project1;
{
文件定义
:
一个名为
Project1
的项目文件
}
uses
{
在
program
中需要使用到哪些单元
}
Forms,
Unit1 in
'Unit1.pas'
{Form1}
,
Dialogs;
{
在这里可以定义一些变量和常量
}
var
AppMsg: String
;
{$R *.res}
{$R
是一个编译指令
,
此处表示要编译资源文件
Project1.res}
{
这个部分可以实现一个函数和过程
}
procedure
AppStart(AppMsg: String
);
begin
ShowMessage(AppMsg);
end
;
{begin…end
部分是
program
的主体
,
这里面的代码是可以运行的
}
begin
{
应用程序初始化
}
Application.Initialize;
Application.Title := 'lxpbuaa';
{
创建主窗体
}
Application.CreateForm(TForm1, Form1);
AppMsg := '
应用程序马上开始运行。
';
AppStart(AppMsg);
{
应用程序开始运行
}
Application.Run;
end
.
一个单元文件被关键字
unit
标识,因此,在这里我将单元文件的源代码称作
unit
。以下是一个完整的
unit
:
unit
Unit1;
{
文件定义
:
一个名为
Unit1
的单元文件
}
interface
{
在这个部分声明可供其他单元使用的变量、常量、类型、函数和过程
}
uses
{interface
部分的
uses
内容对整个单元都有效
}
Windows, Messages, Classes, Controls, Forms, Dialogs, Contnrs;
type
{
声明类型
}
TForm1 = class
(TForm)
private
procedure
ShowInfo(Info: String
);
public
{ Public declarations }
end
;
{
声明函数和过程
}
procedure
ShowInfo(Info: String
);
var
{
声明变量
}
Form1: TForm1;
implementation
{
在这个部分完成单元的私有声明
,
并实现
interface
声明的类、函数和
uses
{implementation
部分的
uses
内容只对
implementation
有效。
SysUtils, Variants;
var
{implementation
部分可以和
interface
部分一样进行声明
}
ObjList: TObjectList;
{$R *.dfm}
{
编译对应的
dfm
文件
}
{
实现
interface
部分声明的函数和过程
}
procedure
ShowInfo(Info: String
);
begin
ShowMessage(Info);
end
;
{
实现
interface
部分声明的类
}
{ TForm1 }
procedure
TForm1.ShowInfo(Info: String
);
begin
ShowMessage(Info);
end
;
{
单元初始化部分
}
initialization
ObjList := TObjectList.Create;
{
单元终止部分
}
finalization
FreeAndNil(ObjList);
end
.
从上面的
Unit1
单元可以看到,一个
unit
可以包含五个部分:
(
1
)
unit
关键字部分,指定单元的名字。
(
2
)
interface
部分。从关键字
interface
到
implementation
为止的内容,都是属于这个部分。该部分可以声明变量、常量、类型、函数和过程,而且它们对于其他单元都是可见的。
(
3
)
implementation
部分。在这个部分也可以完成
interface
具有的声明功能,但是它们对于其他单元是不可见的,属本单元私有;同时完成类、函数和过程的实现。
以上三个部分是一个
unit
必须的。接下来的两个部分是可选的。
(
4
)
initialization
。在这个部分可以完成单元的初始化工作。如果将一个单元比作一个类,我们知道类的初始化是在构造函数
Create
中完成的,所以
initialization
部分就相当于单元的构造函数。
(
5
)
finalization
。在这个部分可以完成单元的终止,完成类似于类的析构函数
Destroy
的功能。
需要注意的是:如果几个单元都有
initialization/finalization
部分,则它们的执行顺序与这些单元在
program
的
uses
字句中的出现顺序一致。所以应该避免
initialization/finalization
部分的代码执行时依赖于它们的执行顺序。
单元循环引用
Unit
的组织结构
过程
}
interface
不需要而
implementation
需要的单元应该在这里引用
}
单元不能被循环引用
(
Circular unit reference
)
的。循环引用的意思是
:
A
引用了
B
,
而
B
又引用
A
,
且都是在
interface
部分进行引用。如下面的单元通不过编译:
unit
Unit1;
interface
uses
Unit2;
……
unit
Unit2;
interface
uses
Unit1;
……
但是如果引用不全发生在
interface
部分,即至少有一个在
implementation
部分,则是允许的。因此,当你需要两个单元相互引用时,应该将其中的一个引用放置在
implementation
部分,否则不能通过编译。
为了避免将来可能的循环引用,对于只在实现部分使用的单元,通常我们都将它写在
implementation
而不是
interface
部分。例如我们编写一个取得一个整型动态数组中最大的元素,需要用到
Math
单元的
Max
函数,此时代码书写应该按照如下所示:
unit
Unit2;
interface
{
因为在声明部分只有一个函数
GetMax
,
只须引用
System
单元
,
而该单元是自动引用的
,
所以
function
GetMax(IntDynArray: Array
of
Integer): Integer;
implementation
uses
Math;
{
在这里而不是接口部分引用单元
Math}
function
GetMax(IntDynArray: Array
of
Integer): Integer;
var
L,I: Integer;
begin
Result := 0;
L := Length(IntDynArray);
if
L = 0 then
Exit
else
begin
Result := IntDynArray[Low(IntDynArray)];
for
I := Low(IntDynArray)+1 to
High(IntDynArray) do
Result := Max(Result, IntDynArray[I]);
end
;
end
;
end
.
在源代码中
,
接口部分没有任何引用单元的代码行
}