Delphi探索

一:过程类型
  ⒈什么是过程类型
把一个变量声明为过程类型,可以把一个过程或函数作为一个整体赋给这个变量或者把这个变量作为
参数传递给其它过程或函数。

声明一个过程类型的语法同声明一个过程或函数的首部语法相似,不同的是在保留字Procedure或fun-
ction后不需要有过程或函数的标识符,例如:

Type
       Proc1=Procedure;
       Proc2=Procedure(VarX,Y:integer);
       Proc3=Function(X:Double):Double;

上例中,声明了三个过程类型,第一个是不带任何参数的过程,第二个是带两个参数的过程,第三个是
带一个Double类型的参数并返回Double类型值的函数。

同声明一个过程或函数一样,您在声明一个过程类型时可以指定一种调用约定方式,缺省就是Register
方式。

下面我们举例说明过程类型的用法:

Type
       SwapProc=Procedure(Var X,Y:Integer);
       MathFunc=Function(X:Double):Double;

{以上是类型声明部分}

Var
       P:SwapProc;
       F:MathFunc;

{以上把P说明为SwapProc 类型的变量,把F说明为MathFunc类型的变量}

Procedure Swap(var A,B:integer);
Var
       Temp:Integer;
Begin
       Temp:=A;
       A:=B;
       B:=Temp;
End;

Function Tan(Angle:Double);
Begin
       Tan:=Sin(Angle)/Cos(Angle);
End;

{以上定义了一个过程和一个函数}


P:=Swap;
F:=Tan;

{以上把Swap过程赋给P变量,把Tan函数赋给F变量}


P(I,J); {相当于调用Swap(I,J)}
X:=F(X); {相当于X:=tan(X)}

这里举例说明了一个过程或函数可以赋给一个过程类型的变量,事实上过程类型的数据还可以作为参
数传递给其它过程或函数。

注意:不能把过程类型直接作为函数的返回类型,不过您可以让函数的返回类型为指针类型,让指针
指向一个过程或函数的地址。

当把一个过程或函数赋给一个过程类型的变量时要注意赋值相容,只有满足下列条件才是赋值相容的。

调用约定方式必须相同。

参数个数必须相同,相应的其数据类型必须相同,但参数名不一定必须相同。

函数的返回类型必须相同。

Object Pascal规定,nil同任何过程类型相容。

过程类型根据其是否运用于对象分为两大类:一类是全局过程指针,另一类是方法指针。

全局过程指针指向的是全局的过程或函数,例如上例中的SwapProc和MathFunc,这类过程类型在声明时
没有Of object 部分。

方法指针在明时必须加上Of object,表示它所指向的是一个对象的方法,程序示例如下:

Type
       TNotifyEvent=Procedure (Sender:Tobject) Of Object;

有了方法指针后,要扩展一个对象,不需要重新派生出一个新的,只要把其它对象的方法赋给个这个
方法指针就可以了,这样可以避免对象的层次过多。

方法指针通常用于把对象的事件同一段已有的代码(可能是其它对象的)相联系起来,例如您想定义
用户单击按钮时的缺省行为,您不必从 Tbutton对象派生出一个新对象并重载它的响应单击的行为,
您只需要把一段已有的代码同一个方法指针联系起来。

方法指针的示例如下:

Type
       TNotifyEvent=Procedure(Sender:Tobject) Of Object;
Type
       TAnObject=Class(TObject)
              FOnClick:TNotifyEvent;
       End;
       TAnOtherObject=Class(TObject)
              Procedure AMethod(Sender:Tobject);
       end;
Var
       AnObject:TAnObject;
       AnOtherObject:TAnotherObject;
Begin
       AnObject:=TAnobject.Create;
       AnotherObject:=TAnotherObject.Create;
       AnObject.FOnClick:=AnotherObject.Amethod;
end;


二:类型相容和赋值相容
  ⒈类型相容
以上详细介绍了Object pascal语言中的数据类型,这里首先要指出的是,Object Pascal是一门类型
严谨的语言,不是所有类型的数据都可以彼此赋值的。例如,一个C语言的程序员,习惯于把一个整
数值赋给一个字符型变量或者把一个实数赋给一个整型变量,这些操作在C语言里是允许的,而在
Object Pascal中,编译器将报错。那么是不中非要数据类型完全一致才能彼此赋值吧?也不是,例
如把一个整型数赋给一个实型变量是允许的,因为赋值过程中数据精度没有损失。总的原则是,只有
赋值号两边的类型是赋值相容的,才可以进行赋值操作。



类型相容

在讨论赋值相容前,我们先介绍类型相容的概念,因为类型相容是赋值相容的前提条件,只有类型相
容的变量才可以进行关系运算。

最容易理解的是当两边的类型完全一致时,赋值总是可以进行的,问题是怎样才算类型完全一致,习
惯于C语言的程序员一定要注意,Object Pascal中的类型完全一致有其特殊的规定。

当满足下列两个条件之一时,可以认为类型T1和类型T2是类型一致的:

T1和T2有完全相同的类型标识符。

T1被声明为与T2等价的类型。

例如下面3种类型是一致的:

T1=Integer;

T2=Integer;

T3=T1;

T1和T2类型一致,是因为它们有完全相同的类型标识符,T3和T1类型一致,是因为T3被声明与T1等价
的类型。

注意:下面的两个类型不是一致的,尽管它们的类型描述完全相同:

T1:Array[1..100] of Integer;
T2:Array[1..100] of Integer;

要使T2成为与T1一致的类型,应该这么写:

T1,T2:Array[1..100] of Integer;

下面我们讨论类型相容的概念,Object pascal规定,满足下列条件之一的认为是类型相容:

两种类型是一致的类型。

两种类型都是实型。

两种类型都是整型。

一种类型是另一种类型的子界。

两种类型都是同一种宿主类型的子界。

两种类型都是基类型相容的集合类型。

两种类型都是紧凑的字符串类型,其元素个数必须相同。

一种类型是字符串类型,另一种可以是非紧凑或紧凑的字符串类型或者是字符类型。

一种类型是指针类型,另一种是其它指针类型。

两种类型都是类类型或类引用类型,并且其中一种类型是另一种类型的继承者。

一种类型是PChar类型,另一种类型是零基准的字符数组Array[0..n] of Char。

两种类型是指向同一种类型数据的指针(编译开关$T处于($T-)状态)。

两种类型都是过程类型,参数个数相同,参数类型分别一致,如果是函数还要求返回类型一致。

一种类型是Variant类型,另一种类型是整型或实型或字符串类型或布尔型。
 

⒉赋值相容
满足类型相容的仅仅可以进行关系运算,只有赋值相容的变量才是可以赋值的或进行参数值的传递,假
设T1和T2是两种类型,要把T2类型的值赋给T1类型的变量,object Pascal规定,满足下列条件之一的
可以认为是赋值相容  :

T1是一个对象类型,T2是它的祖先对象类型。

T1和T2是一致的类型,但不能是文件类型或包含文件类型元素的构造类型。

T1和T2是相容的有序类型,并且T2的值域被完全包围在T1的值域中。

T1和T2都是实型,并且T2的值域被完全包围在T1的值域中。

T1是实型,T2是整型。

T1和T2都是字符串类型。

T1是字符串类型,T2是字符类型。

T1是字符串类型,T2是紧凑的字符串类型。

T1是长字符串类型,T2是PChar类型。

T1和T2是相容的紧凑字符串类型。

T1和T2是相容的集合类型,并且T2的值域被完全包围在T1的值域中。

T1和T2是相容的指针类型。

T1是类类型,T2是从T1继承的类类型。

T1是类费用类型,T2是从T1继承的类引用类型。

T1是Pchar类型,T2是字符串常量。

T1是Pchar类型,T2是零基准的字符数组array[0..n] of Char。

T1和T2是相容的过程类型。

T1是过程类型,T2是一个过程或函数,并且两者的参数个数相同,参数类型分别一致,如果是函数,还
要求返回类型一致。

T1是Variant类型,T2是整型或实型或字符串类型或布尔型。

T1是整型或实型或字符串型或布尔型,T2是Variant类型。

赋值相容是进行赋值或参传递的先决条件,当参数是变量参数时(关于变量参数的概念请参见变量)。
要求还要严格,它要求形参和实参的类型必须一致。


三;类型强制转换
⒈数值的类型强制转换
您可以把一种类型的数值强制转换成另一种类型的数值,语法如下:

类型标识符(表达式)

数值的类型强制转换首先要指定一个类型标识符,然后把要转换的表达式用()括起来,例如:

Integer('A')
Char(48)

上例中,分别把字符A转换成一个整数,把一个整数48转换成字符。

注意:Object Pascal规定,类型标识符和括号内的表达式要么同时是有序类型,要么同时是指针类型。


⒉变量的类型强制转换
您也可以把一种类型的变量强制转换成另一种类型的变量,包括过程类型的变量,语法如下

类型标识符(变量引用)

变量的类型强制转换是针对变量引用而言的,Object Pascal规定,要转换的变量类型的长度必须与目
标类型的长度一一致,如果不一致将引起异常。

如果类型强制转换是通过As操作符进行的,As操作符能在转换前先进行是否赋值兼容的检查。如果是通
过类型标识符进行类型强制转换 ,则不进行检查。

程序示例如下:

Type Func=Function (X:Integer):integer;
Var
       F:Func;
       P:Pointer;
       F:=Func(P);
       {把指针类型的变量P转换成func类型的变量F}
       Func(P):=F;
       {首先把指针的变量P转换成Func类型,然后把一个func类型的值赋给转换后的变量P。}


四:变量
⒈变量的声明
类型和变量是两个既有区别又有联系的概念。一般来说,类型是不能直接参加运算的(后面要讲到,
类型可以在不声明一个对象实例的情况下直接使用,参见类类型描述),您必须声明了一个指定类型
的变量以后,才能对该类型的数据进行运算。

在Object Pascal中,声明变量的语法如下:

Var
       变量1:类型;
       变量2:类型;
       …
       变量n:类型;

变量是通过保留字Var声明的,Var后面可以同时声明多个变量,如果其中部分变量的类型相同,也可
以合并在一起,彼此之间用逗号隔开。

声明变量要注意两点,一是变量名要符合Object Pascal语言关于标识符的规则,二是必须明确指定变
量的类型,类型要么是Object pascal语言预定义的标准类型,要么是前面已声明过的自定义类型。

程序示例如下:

Type Digits=Set of 0..9;
Var X,Y,Z:integer;:{X,Y,Z类型相同,把它们合并在一起声明}
       M,N:Digits;{Digits类型已经在前面声明}

Object Pascal允许把类型的和变量的声明合二为一,这样可以简化程序,例如上例中,变量M和N可以
这样声明:

Var M,N:Set of 0..9;

从语法示意图还可以看出,声明变量时还可以给该变量赋一个类型常量。


⒉Absolute子句
声明变量时还可以带一个可选的Absolute子句,用于指定变量的值在内存中存贮的绝对位置。Absolute
子句的语法如下:
Absolute 无符号整型:无符号整型
这个指示字后可以跟一个段值和一个偏移量,如:

Var CrtMode:Byte Absolute $0040:$0049;

上例中,声明了一个BYTE类型的变量CrtMode,这个指示字后第一个常数是段值,第二个常数是偏移量,
段和偏移量只能在$0000至$FFFF之间。

注意:这种形式不能用于WINDOWS的保护模式下,因为WINDOWS不允许您的应用程序访问程序外的内存区域。
直接写入内存地址会导致一个GPF错误,实际上,在WINDOWS中,一般是声明一个另一变量,然后在这个子
句中指定变量的值的存贮地址跟该变量相同,例如:

Var Str:String;
    StrLen:Byte Absolute Str;

上例中,先声明了String类型的变量Str,然后声明了一个Byte类型的变量Strlen,Absolute子句指定变量
StrLen的地址跟变量Str的地址相同。

⒊全局变量和局部变量
全局变量分为两在类,一是整个程序都能访问的公共变量,必须在单元的interface部分声明,另一类是只
限于某个单元访问的公共变量,必须在该单元的Implementation部分声明,对于全局变量,您可以在声明的
同时赋一个初始,例如:

Var X:integer=1;

没有显式地赋初值,这个全局变量的初始值就是0。

局部变量的作用域只限于声明所在的块内,通常是在过程、函数或类的方法内部声明,例如:

Procedure MyProc:
Var X,Y,Z:integer;
Begin
       …
End

上例中,X,Y,Z只是在过程MyProc内有定义。

对于局部变量而言,不能在声明时赋初值,在明确地给它们赋值之前,它们的值是不确定的。


五:类型常量
⒈简单类型的常量
简单类型的常量是指常量的值为简单类型(有序类型和实型)的类型常量,例如:

Const
       Maximum:integer=9999;
       Factor:Real=-0.1;
       BreakChar:Char=#3;

上例中,声明一个整型的常量Maximum,一个实型的常量Factor,一个控制字符型的常量BreakChar。


⒉指针类型的常量
指针类型的常量通常是用"常量地址表达式"来声明的,对于Pchar类型的类型常量,可以用一个字符串赋值。

指针类型的常量示例如下:

Type
       TDirection=(Left,Right,Up,Down);
       PNode=^Node;
       TNode=Record
              Next:PNode;
              Symbol:String;
              Value:TDirection;
End;

Const
       N1:TNode=(Next:nil;Symbol:'DOWN';Value:Down);
       N2:TNode=(Next:@N1;Symbol:'UP';Value:Up);
       N3:TNode=(Next;@N2;Symbol:'RIGHT';Value:Right);
       N4:TNode=(Next;@N3;Symbol:'LEFT';Value:Left);

Const
       DirecTionTable:PNode=@N4;

上例中,首先声明了一个枚举类型TDirection,一个指针类型PNode,一个记录类型TNode,其中Next
字段是PNode类型。

然后声明了四个记录类型的常量,其中Next 字段的值是用指针类型的常量给出的,N1的Next字段的值
是nil,诸如此类。

最后声明了一个指针类型的常量DirectionTable,它的值是记录常量N4的地址。


⒊过程类型的常量
过程类型的常量声明的语法如下:

Const 常量名称:过程类型=初始值;

声明一个过程类型的常量只需给出过程或函数名,给出的过程或函数必须与常量的类型赋值兼容,也就
是说,参数个数和顺序以及参数的类型必须一致,否则只能指定nil.

程序示例如下:

Type
       TErrorProc=procedure (ErrorCode:Integer);

Procedure DefaultError(ErrorCode:Integer);

Begin
       WriteLn('Error',ErrorCode,'.');
End;

Const
       ErrorHandler:TErrorProc=DefaultError;

上例中,首先声明了一个过程类型TErrorProc,然后定义了一个名为DefaultError的过程,最后声明
了一个过程类型的常量ErrorHandler,它的值是DefaultError过程。


⒋构造类型的常量
如果要声明一个构造类型的常量,必须给出构造类型的各个分量的值,实际上我们已经介绍了记录类
型的常量,除了记录类型的常量之外,还可以声明数组类型和集合类型的常量,但不能明文件类型的
常量或包含文件类型分量的记录类型的常量。

声明一个数组类型的常量必须给出所有的元素,其语法如下:

Const 常量名=(分量值1,分量值2...分量值n);

数组类型的常量的各个元素由一对圆括号括起来,每个分量之间用逗号分隔。例如:

Type
       TStatus=(Active,Passive,Waiting);
       TStatusMap=Array [TStatus] of string;
Const
       StatStr:TStatusMap=('Active','Passive','Waiting');

上例中,首先声明了一个枚举类型TStatus,然后声明了一个数组类型,其下标类型是TStatus,其基
类型是String,最后声明一个TStatusMap类型的数组类型常量,它的三个元素的值分别是'Active',
'Passive',"Waiting'。

对于基类型是字符的数组,在声明时可以用一个字符串作为常量的值,例如:

Type
       TStatusMap=Array [1..11] of Char;
Const
       StatStr:TStatusMap='This is way';

要声明集合类型的常量,常量的值是用方括号括起来的集合常量,例如:

Type
       Digits=Set Of 0..9;
       Letters=Set Of 'A'..'Z';
Const
       EvenDigits:Digits=[0,2,4,6,8];
       Vowels:Letters=['A','E','I','O','U'];

上例中,首先声明了两个集合类型,然后声明了二个集合类型的常量,如EvenDigits表示偶数的集合,
Vowels表示元音字母的。

要声明记录类型的常量,必须给出记录的各个字段的值,例如:

Type
       Tpoint=Record
       X,Y:Single;
end;
TVector=Array[0..1] of TPoint;
TMonth=(jan,Feb,Mar,Apr,May,Jun,Jly,Aug,Sep,Oct,Nov,Dec);
Tdata=Record
       D:1..31;
       M:Month;
       Y:1900..1999;
end;
Const
Origin:TPoint=(X:0.1;Y:0.2);
Line:TVector=((X:-3.1;Y:1.5),(X:5.8;Y:3,0));
SomeDay:TData=(D:2;M:Dec;Y:1969);

上例中,实现声明一个记录类型TPOINT,它有两个字段X,Y,相应地声明类型常量Origin时,给出X字
段的值为0.1,Y字段的值为0.2。Line这个类型常量就复杂些,首先TVector是个基类型为TPoint的数
组,相应地声明类型常量Line时,首先按声明数组类型常量的要求给出它的两个元素的值,其中每个
元素又是一个记录类型,因此又必须分别给出每个字段的值。

声明记录类型的常量时要注意,字段的顺序必须与记录类型声明时的顺序一样,并且记录类型中不能
包括文件类型的分量。

综合合我们介绍的各种类型常量,您可以发现,类型常量的声明跟变量的声明很相似,事实上在程序
中类型常量可以当作变量使用,只是要注意一点,类型常量的值是不能改变的。


六:可变类型
⒈什么是可变类型
  从Delphi2.0起引起了一个新的数据类型Variant,它的确切类型在运行期是可变的,也就是说它可以
表示某些其它类型的值(除了Variant类型本身)。Variant类型主要用于当数据的类型在编译期是不确
定的或在运行期可能变化的情况。Variant类型具有如下特点:

Variant类型不但可以表达一般的数据类型如整型、实型、字符串型、布尔型,还可以表示OLE自动化对
象,还可以表示长度和维数可变的数组。

Variant类型变量在被声明后总是被初始化为一个特殊的值Unassigned,表示该变量还没有赋值,如果
变量的值为Null,表示该变量的值是未知的或错误的。

Variant类型的变量可以同一般类型的数据出现在同一个表示式中,编译器将根据需要自动进行类型转
换。

当Variant的变量表示一个OLE自动化对象时,可以通过这个Variant类型的变量引用对象的特性和方法
等。

注意:尽管可变类型提供了许多编程上的灵活性,但要占用更多的内存空间和运行时间。




■Object Pascal语言的数据类型到这里已经全部讲述完毕,从下一章开始我将讲述:Object Pascal语
言的语句  


附录:Turbo Pascal编年史

出版年代
版本名称
主要特色

1983
Turbo Pascal 1.0

Turbo Pascal 2.0

Turbo-87 Pascal
提高实数运算速度并扩大值域

1985
Turbo Pascal 3.0
增加图形功能

Turbo BCD Pascal
特别适合应用于商业

1987
Turbo Pascal 4.0
提供集成开发环境(IDE),引入单元概念

1988
Turbo Pascal 5.0
增加调试功能

1989
Turbo Pascal 5.5
支持面向对象的程序设计(OPP)

1990
Turbo Pascal 6.0
提供面向对象的应用框架和库(Turbo Vision)

1992
Turbo Pascal 7.0
面向对象的应用系统、更完善的IDE

Turbo Vision 2.0

1993
Borland Pascal 7.0
开发 Object Windows库、

(For Windows)
提供对OLE多媒体应用开发的支持

1995
Delphi
Visual Pascal
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1章 com部分 1.1 activex部分 1.1.1 activex控件之消失的事件 1.1.2 创建acfivex控件之高级编辑界面 1.1.3 数据库明了的acfivex控件 1.2 基于com的office开发 1.2.1 office自动化编程 1.2.2 创建office2000插件 1.3 基于com的数据库开发 1.3.1 adox的数据库开发 1.3.2 sqlserver-dmo数据库开发 1.3.3 ole结构化存储及其在公文包型数据库中的应用 第2章 shell部分 2.1 外壳扩展 2.1.1 搜索扩展 2.1.2 文件飞跃提示扩展 2.1.3 拖放控制扩展 2.1.4 命名空间扩展 2.1.5 实现autocomplete 2.1.6 属性页扩展 2.1.7 外壳执行操作记录器 2.2 未经公开的外壳奥秘 2.2.1 pltemldlist的基本概念 2.2.2 用外壳接口对系统进行管理 第3章 ide扩展部分 3.1 opentoolsapl简介 3.2 helloworld 3.3 消息通知器 3.4 将winamp集成到delphi中 3.5 自动规范控件前缀命名的专家 3.6 to-dolist的增强 第4章 ie扩展部分 4.1 ie菜单扩展 4.2 ie按钮扩展 4.3 阻断弹出式广告的bho 4.4 ie右键菜单扩展 4.5 ie下载扩展 4.6 创建3721样式的google搜索扩展 4.7 ie异步可插入协议扩展 4.8 创建可自动填表的ie面板插件 第5章 vcl深度探索 5.1 action开发之七种武器 5.2 vcl拖放高级应用 5.3 高级停靠技术的实现 5.4 面向对象的界面复用技术 5.5 vcl中的容器类 5.6 所见即所得的delphiweb开发利器--intraweb开发指南 5.7 基于bold的uml模型驱动的数据库应用开发 5.7.1 object rdbms mapping原理简介 5.7.2 使用bold开发数据库应用 5.7.3 bold的代码迭代开发 第6章 delphi与设计模式 6.1 使用delphi实现设计模式 6.1.1 工厂模式 6.1.2 单例模式(singleton) 6.1.3 建造模式(builder) 6.1.4 原型模式(prototype) 6.2 结构模式 6.2.1 适配器模式(adapter) 6.2.2 合成模式(composite模式) 6.2.3 装饰模式(decorator模式) 6.2.4 门面模式(faqade模式) 6.2.5 桥模式(bridge模式) 6.2.6 代理模式(proxy) 6.2.7 享元模式(flyweight模式) 6.3 行为模式 6.3.1 策略模式(strategy模式) 6.3.2 模板模式(template method模式) 6.3.3 责任链模式(chain of responsibility模式) 6.3.4 观察者模式(observer模式) 6.3.5 命令模式(command模式) 6.3.6 备忘录模式(memento模式) 6.3.7 迭代子模式(iterator模式) 6.3.8 访问者模式(visitor模式) 6.3.9 调停者模式(mediator模式) 6.3.10 状态模式(state模式) 第7章 工具篇 7.1 极限编程的集成测试工具-dunit 7.2 性能分析工具gpprofile 7.3 内存泄漏清道夫--memproof 7. 4 codesite应用指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值