没有合适的资源?快使用搜索试试~ 我知道了~
Delphi6应用开发指南-第五章(集合、常数)
需积分: 9 0 下载量 152 浏览量
2012-03-07
18:25:49
上传
评论
收藏 984KB PDF 举报
温馨提示
试读
22页
Delphi6应用开发指南
资源推荐
资源详情
资源评论
第 5 章 集合、常数与运行时类型信息编程
定义好的抽象,可以解决许多编程方面的障碍。在面向对象语言中,所谓的抽象就是“创建类”。在
某种程度上确实如此。许多项目的失败就是因为创建的类太少,结果形成了一些庞大的类,它们做的事情
太多,因而难于维护。
好的抽象也可以在较低层次上定义。像 Delphi 这样的强类型化编译器、定义在问题域中有具体意义的
类型等,都可能是有帮助的。一般的,进行较为精确的类型定义,通常可以更好地定义类的属性。大多数
属性的特征可以通过整数和数组进行表达,但相比而言,由内建类型派生而来的集合、范围、常数、数组
以及枚举等更有意义。
Object Pascal 是一种具有很强的表达能力的面向对象编程语言,它有助于定义在特定问题域的上下文
中具有意义的类型。例如,如果只有某个特定范围内的值有意义,就定义范围、集合或枚举类型来命名这
些值所代表的数据。本章示范了如何使用 Object Pascal 中的这些概念,以有助于定义好的抽象。这些技术
可以使您的代码具有更强的可读性,而且比使用内建数据类型所需的错误检查代码要少。
5.1 不可变常数
常数很好用。常数是现存的最为可靠的代码之一。定义常数之后,无论如何其值都是可以依赖的。不
用担心,不存在偶然或有意的误用。在 Delphi 中有许多方法来使用常数,以使得代码更加可靠。
注意:Delphi 支持类型化常数,它们的值是可变的。关于可赋值的常数,更多的信息请参见
5.1.3 节“使用 const 创建静态本地变量”。
5.1.1 全局与本地常数
当变量定义在本地作用域中时,可以访问该作用域的代码均可使用该变量。临时使用全局或本地变量
可能导致有害的问题,特别是对于多线程应用程序,其中一个线程可能依赖于某个值,而另外一个线程正
在改变该值。如果一个值需要保持不变,则应该用 const 来表示。全局常数是定义在单元的接口部分的常
数。而本地常数是定义在实现部分的常数。
另外,可能会在许多地方重用的值应该定义为常数。假定 Pi 的值在您的整个程序中都是有意义的,则
应在接口部分将名字 Pi 作为常数引入,并将其值初始化为具有正确的有效数字位数的 Pi 值,以满足您的
需要。
注意:新的单元 ConvUtils.pas 包含有数以百计的常数和转换单元。尽管它包含了秒差距与
米的转换常数值,但并未包含 Pi 的常数值。System.pas 单元中包含了函数 Pi,返回 Pi 值
的 extended 类型的浮点值。
我们的目标是在尽可能狭窄的作用域中定义常数。如果一个常数只在过程块中需要,那么该过程就是
合适的作用域。使作用域变窄背后的思想在于,要尽量减少使用代码的程序员在理解代码目的时所需要进
行思考的事物的数目。常数的语法部分依赖于其所定义的上下文。本地、全局、过程常数的通常形式如下:
const name = value;
或,
const name : type = value;
const 是关键字,表示其后是常数。对于一个常数列表中的所有常数,仅需要键入 const 一次。例如,
在实现部分定义三个常数,如下所示。
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
第 5 章 集合、常数与运行时类型信息编程 108
implementation
const
I : Integer = 3;
S = 'Bachman Turner Overdrive';
F : Double = 4000000000000.0;
有许多途径来使用常数,可以使得程序更加可靠。对于常数的所有变体的语法规则,请察看上下文帮
助,在索引中查找 grammar。更多的例子见下文。
5.1.2 常数参数
当过程不应改变某个参数的值时,应把该参数声明为常数参数。如果包括了 const 限定符,可以保证
该值不被改变。保证总是难于得到,因此能够得到保证确实不错。常数参数可以有默认值。下面的代码演
示了具有默认值的常数参数。
procedure DisplayBandName( const Value : String = 'R.E.O.' );
begin
ShowMessage( Value );
end;
Procedure SomeProc;
const
BTO = 'Bachman Turner Overdrive';
begin
DisplayBandName;
end;
DisplayBandName 过程中定义了一个具有默认值的参数。如果不传递参数,Valu e 参数的值将是
‘R.E.O.’。如果把常数 BTO 传递给 DisplayBandName,那么 ShowMessage 函数将显示 Bachman Turner
Overdrive。常数参数的存在保证了调用的方法不会在无意中改变传递的参数值。使用 const 要远胜于希望
和祈祷。
5.1.3 使用 const 创建静态本地变量
定义在过程中的变量在栈上分配内存空间。常数通过编译嵌入到代码中,只存在于所定义的过程中。
当过程调用或退出时,栈内存空间像手风琴一样来回伸缩。通常,在过程中引入的名字具有过程作用域。
即,该名字和值只在所定义的作用域中可访问。有时,您可能需要各种占位符,即只在过程作用域可访问
的名字,而在过程返回后依然保持其值。C 和 C++称之为静态变量。Delphi 用可赋值常数来产生同样的效
果。
使用下面的语法您可以定义一个变量,它看上去是常数,但实际上是可变的静态变量。
Procedure MutableConst;
const
I : Integer = 0;
begin
Inc(I);
ShowMessage(IntToStr(I));
end;
// ...
for I := 0 to 3 do MutableConst;
在上面的 MutableConst 过程中定义一个类型化的可赋值常数,常数的值在该过程的各次调用之间仍然
可以保持。最后一行的 for 语句调用 MutableConst 四次,最后一次调用在 ShowMessage 的对话框中显示值
为 4。默认情况下,类型化常数是可赋值的。可以通过$J+编译器指令进行改变;或者在 Project Options 对
话框中的 Compiler 属性页中改变 Assignable typed constants 复选框,如图 5.1 所示。
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
第 5 章 集合、常数与运行时类型信息编程 109
图 5.1 默认情况下,类型化常数是可赋值的,并且可以在对其所定义的过程的后续调用之间维持其值。要使
其不可赋值,对 Project Options 对话框中的 Compiler 属性页的 Assignable typed constants 复选框取消选
定即可。默认情况下,该复选框是选定的
可赋值类型化常数使得可以在过程中定义占位符,每次该过程调用时都可以维护该值。通过使用可赋
值类型化常数,可以模拟静态特性(有关静态特性的更多知识,请阅读第 7 章)。
5.1.4 数组常数
对您的武器库来说,数组常数是另外一项可以添加的工具。也许您不会每天都用到数组常数,但在日
常编程中确实有一些数组常数的例子。考虑下列例子。
Procedure ArrayExamples;
const
DaysOfWeek : array[1..7] of string = ('Sunday', 'Monday', 'Tuesday',
'Wednesday', 'Thursday', 'Friday', 'Saturday' );
MonthsOfYear : array[1..12] of string = ('January', 'February', 'March',
'April', 'May', 'June', 'July', 'August','September', 'October',
'November', 'December' );
EXAMPLE1 = 'February 12, 1966 occurred on a %s';
EXAMPLE2 = 'The fourth month is %s';
var
Output : string;
Day : Integer;
begin
Day := DayOfWeek( StrToDate('02/12/1966'));
Output := Format( EXAMPLE1, [DaysOfWeek[Day] ] );
ShowMessage( Output );
Output := Format( EXAMPLE2, [ MonthsOfYear[4] ] );
ShowMessage(Output);
end;
DaysOfWeek 数组包含了 7 个元素,都是字符串。MonthsOfYear 数组包含了 12 个元素,也都是字符串。
两个数组都初始化为常数数组。Begin 块语句的第 2 行使用星期中某天对应的数字来索引数组。第 1 次调
用 ShowMessage 过程的输出为‘February 12, 1966 occurred on a Saturday’。Begin 块语句的第 4 行对该年的
月份执行了一个简单的操作。
当然您也可以把上面的代码写成由嵌套 if 条件测试组成的 case 语句,但常数数组在紧凑的操作中生成
了优化而更小的代码。考虑下一个例子,其中用 if 条件测试来比较激活状态以设置控件的背景颜色,也提
供了用数组实现的相同功能的代码。
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
第 5 章 集合、常数与运行时类型信息编程 110
if( Edit1.Enabled = False ) then
begin
Edit1.Enabled := True;
Edit1.Color := clWhite;
end
else // True
begin
Edit1.Enabled := False;
Edit1.Color := clBtnFace;
end;
上面的代码计算了 TEdit 控件(随机选定)的 Enabled 状态,对该状态取反,并相应地设置颜色。该
代码实用而直接,但使用常数数组可使之更为有效。使用常数数组的修订版本如下。
const
Colors : array[Boolean] of TColor = (clBtnFace, clWhite);
begin
Edit1.Enabled := Not Edit1.Enabled;
Edit1.Color := Colors[Edit1.Enabled];
end;
常数数组使得我们可以将代码缩减到原来的五分之一。使用单目 not 操作符来执行 Enabled 状态的切
换,用 Enabled 特性的布尔值来索引常数数组 Colors。在使用布尔值作索引时,False 的值较小。上面的代
码更加紧凑,既小且快。下一节的内容是有关记录常数的,阅读时请注意其中一个用到记录数组常数的例
子。
5.1.5 记录常数
记录常数是类型为记录的常量数据。一个很普遍的记录是 TPoint。TPoint 在笛卡尔坐标系中定义了两
个坐标。TPoint 在 Windows.pas 单元中如下定义:
TPoint = record
x: Longint;
y: Longint;
end;
要初始化常量记录,需要以 fieldname : value 的形式指定每个字段,每个字段的名字与值用冒号分
隔。这里有一个例子。
const Point : TPoint = (X:100; Y:100);
常量记录数组需要初始化每个数组元素,对于构成记录值的字段,将名字和值对的集合用括弧括起来。
这里是一个由四个点构成的数组。
const
Points : array[0..3] of TPoint = ((X:10;Y:10), (X:10;Y:100), (X:100;Y:100),
(X:100; Y:10));
Procedure DrawRect( const Points : Array of TPoint );
var
I : Integer;
begin
Canvas.PenPos := Points[0];
for I := Low(Points) to High(Points) do
Canvas.LineTo( Points[I].X, Points[I].Y );
Canvas.LineTo( Points[0].X, Points[0].Y );
end;
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
第 5 章 集合、常数与运行时类型信息编程 111
由于并未考虑监视器屏幕的高宽比,该数组只是粗略地定义了如图 5.2 所示的正方形。数组 Points 被
传递给代码中的 DrawRect 过程,用以生成如图 5.2 所示的正方形。
图 5.2 利用 LineTo 方法和 TPoint 记录组成的
数组,在窗体的画布上所画出的正方形
通过将一些基本的 Object Pascal 术语联合起来,可以很容易地创建很多种常量数据,用于代表各种各
样的信息。使用记录和数组常数,可以使您的代码更具有表现力。通过把精确定义的数据映射到问题域的
信息,对代码控制得越好,管理数据所需的代码就越少。
5.1.6 过程常数
过程常数是用 const 修饰的名字,其数据类型为过程类型。一般来说,过程类型只是指向过程的指针,
它使得可以把过程和函数赋值给类型与其相匹配的变量和参数。过程类型的更多知识可以阅读第 6 章。一
个过程类型的例子就是定义在 classes.pas 单元中的 TNotifyEvent。下面是 classes.pas 的摘录,给出了
TNotifyEvent 的定义。
type TNotifyEvent = procedure (Sender: TObject) of object;
从列出的代码可以看出,TNotifyEvent 类型是由过程组成的,它们有一个 TObject 类型的参数,名字
为 Sender。类型定义结尾的 of object 表示 TNotifyEvent 类型是被称为方法指针的特定过程类型。
TNotifyEvent 看起来很熟悉,因为它就是 Object Inspector 中许多事件特性的类型。双击空白窗体,Delphi
将为窗体的 OnCreate 事件特性创建如下的空方法定义。
procedure TForm1.FormCreate(Sender: TObject);
begin
end;
注意:按照惯例,Delphi 使用 On 前缀表示该特性为事件特性。On 暗示着对动作的响应,即
事件。
代码中的 TForm1.部分表示该方法属于 TForm1 类。FormCreate 表示它是 OnCreate 事件的处理程序,
将类名和方法名从定义中剥离,余下的就是 procedure (Sender:TObject),恰好可以与 TNotifyEvent 匹配。
在 Delphi 中选择 OnCreate 事件特性,按键 F1,将显示 CustomForm.OnCreate 的上下文帮助。帮
助文档清楚地指出,OnCreate 定义为特性 OnCreate : TNotifyEvent; 即类型为 TNotifyEvent 的特性。
5.1.7 指针常数
无论使用任何语言,我们的思维都只是受限于用以表达思想的语言以及我们对它掌握的熟练程度。一
些术语可能不像其余的那样常用。指针常量就是其中的一个。在日常的 Windows 应用编程中,指针可能不
太常用,不过 Delphi 并不限制您只能编写典型的 Windows 风格的程序。指针常量就是指向特定地址的指
针。下面的代码琐碎而令人困惑,但它演示了与指针常量有关的必要机制。
type
TDateTimeFunc = function : TDateTime;
const
NowP : Pointer = @SysUtils.Now;
var
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
Click to buy NOW!
P
D
F
-
X
C
h
a
n
g
e
V
i
e
w
e
r
w
w
w
.
d
o
c
u
-
t
r
a
c
k
.
c
o
m
剩余21页未读,继续阅读
资源评论
EYUANatQQdotCOM
- 粉丝: 11
- 资源: 113
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功