`

数据类型

 
阅读更多

构造类型

构造类型是由一个或多个已经实现定义的类型按一定的方法构造而成的新数据类型。Pascal定义了4种基本构造方法,对应4种构造类型:数组型、集合型、记录型、文件型。

另外,作为面向对象的编程语言,Delphi还定义了3种特殊的构造类型:类、类原型、接口。关于这3种类型,我们将在后续的章节进行详细介绍。

(1)数组型

数组是由固定个数的多个元素组成的有序结构,其中所有元素的类型相同。

数组型的定义如下:

type 标识符=array[下标类型] of 数据类型;

其中下标类型应该是顺序类型(枚举性,整型等)。在Delphi中,数组的下标类型部分可以省略,这就是一个长度可变的数组(动态数组)。可以用SetLength语句改变动态数组的长度。

一般,只允许通过数组变量名与相应下标访问数组变量中的一个元素。但当两个数组变量的类型相同时,允许以变量名整体地互相赋值。所谓类型相同是指使用同一个类型标识符,或类型标识符不同但有形为T=P的类型定义。

(2)集合型

集合是相同类型对象的聚集。构成集合的每一个对象称为集合的元素。元素的类型称为集合的基类型。

集合型的定义如下:

type 集合型=set of 基类型;

可以用5种关系运算符=、< >、<=、>=和in来测试集合成员关系。其中运算符in可以测试某个变量是否是集合的成员。

如果有这样一个集合定义:

Chars := ['a','b','c','d','e'];

则表达式('a' in Chars)结果为True,而表达式('x' in Chars)的结果则为False。

集合类型可以进行以下数学运算(设A,B是两个同类型的集合变量):

1)赋值A:=[ ];

2)并A+B,结果是A和B中的所有元素组成的集合;

3)交A*B,结果是A和B中公共元素组成的集合;

4)差A-B,结果是在A中但不在B中的元素组成的集合。

(3)记录型

数组型、集合型都是由类型相同的元素组成的有序结构,在实际问题中还经常遇到由不同类型的元素组成的结构。记录型是由不同类型的多个固定元素组成的数据。

记录型定义如下:

type

标识符=record

域标识符1:类型1;

M

域标识符n:类型n;

end;{record}

(4)文件型

上述的数据类型均是在程序运行期间存在且存储于内存中的数据。计算机在处理问题时,有些数据需要长期保留,这就需要把这些数据存储在外存储器中,如磁盘、磁带等。描述与外部存储设备联系的数据称为文件。

文件是一个具有符号名字的、由相同类型数据组成的数据序列。Pascal语言中的文件型是重要的数据类型之一。

文件型定义如下:

type 文件标识符=file of 数据类型;

其中数据类型可以是除文件型或以文件型为成分的构造类型以外的其他任何类型。

可以把类型定义和文件变量声明合在一起,如:

var

afile :FILE OF integer;

3.指针类型

访问一个内存变量通常有两种方法:一种是通过名字访问,另一种是通过地址访问。指针式通过地址访问变量的一种数据类型。

由于动态数据结构的变量必须在程序执行过程中动态生成,不能预先声明,所以无法预先给这些变量起好名字,也无法通过名字进行访问,因此不能用指针先得到它的地址,然后间接访问它们。

指针类型的定义如下:

type 指针类型标识符=类型标示符;

对指针可以应用比较运算符中的"="和"<>"进行比较。两个指针向同一个动态变量,则两个指针变量相等,否则即为不等。

语句

在程序中,表示算法的是一系列语句。Pascal语句分为两类:简单语句和构造语句。简单语句是指不包括其他语句的语句,构造语句由简单语句按照一定的规则构造而成。

1. 简单语句

(1)赋值语句

形式:

变量:=表达式

复制符号为":="。

(2)复合语句

复合语句是用begin和end括起来的一个语句序列,语句与语句之间用分号隔开。

begin与end要配对使用。begin与end之间括起来的是一个语句整体。在if语句、case语句、with语句、for语句、while语句中的语句部分,使用了一个以上的语句时,都要使用复合语句,以确定这是一个语句整体。

(3)转移语句

转移语句用于改变程序的动态执行顺序,控制程序转到指定位置继续执行,该指定位置由标号表明。

标号为一个语句的前缀,中间用冒号隔开,作用是标记程序的位置。其格式为:

标号:语句

标号必须预先在标号说明部分声明。标号声明的一般形式为:

label 标号;

转移语句的格式为:

goto 标号;

其中goto为保留字,表示使程序转移到标号处,从标号所标记的语句开始,继续执行。为了使程序结构紧凑,思路清晰,程序设计中不提倡使用转移语句。

2. 控制语句

(1)选择性语句

选择性语句包括if语句和case语句,分别用来构成双分支选择结构语句和多分支选择结构语句。

1)if语句

if语句有两种格式。

格式1:

if条件 then 执行一段程序

格式2:

if 条件 then 执行一段程序

else 执行另一段程序

其中,“执行一段程序”和“执行另一段程序”部分还可以嵌套if语句。

if语句会计算一个表达式,并根据计算结果决定程序流程。if保留字后跟随一个生成布尔值True或 False的表达式。一般用“=”,“>”,“<”等作为关系运算符,比较的结果会产生一个布尔型值。当表达式为True时,执行then后的语句,否则执行else后的语句。if语句也可以不含else部分,表达式为False时自动跳到下一行程序。

if语句可以嵌套。当使用复合语句表达时,复合语句前后需加上begin和end。else保留字前不能加“;”,而且,编译器会将else语句视为属于最靠近的if语句。必要时,须使用begin和end保留字来强迫else部分属于某一级的if语句。

应尽量避免使用嵌套的if语句,在不得不使用的情况下应该用多个if语句来判断各种可能。不要使用超过5层的if语句嵌套,应使代码编写得更加清晰明了。

在if/then/else语句中,最常发生的行为应放在then子句中,而其他可能性较小的行为应放在else子句中。

如果在if语句中有多个条件需测试,这些条件应按计算强度由少到多的顺序从左到右排列。这样做能使编译器在编译代码时获得布尔估算逻辑的捷径,从而使代码获得最佳的优化。

2)case语句

case语句也叫做情况语句,它针对多种情况产生多条分支。case语句适用于被判断的变量或属性是整型、字符型、枚举型或子界型时。

在一个case语句中的各个独立的单元应以数字或字母顺序排列。每一个case单元的动作行为应保持简单而不应该超过4~5行代码。如果所要执行的动作过于复杂,应采用独立的过程或函数。

case语句中的else子句只有当需要系统默认行为或处理错误时才使用。

case语句格式如下:

case 表达式 of

情况标号表1:情况子句1;

情况标号表2:情况子句2;

M

情况标号表n:情况子句n;

end

(2)重复性语句

1)repeat语句

repeat语句也称为直到语句。repeat语句的使用同while语句一样,并且遵循同样的规则。格式如下:

repeat

执行一段程序;

until 循环结束条件

下面的示例程序中,当语句被执行时,会循环输出1~10的数字。布尔表达式i=10(注意,与其他语言不同的是,“=”是关系运算符,而不能进行赋值操作)直到repeat...until程序段的结尾才会被计算,这意味着repeat语句至少会被执行一次。

i := 0;

repeat

i := i+1;

Writeln(i);

until i=10;

2)while语句

while语句也叫做当语句。当需要的条件满足时,即进行循环。

格式如下:

while 布尔表达式 do语句

while保留字后面必须跟一个布尔表达式。如果该表达式的结果为真,循环被执行;否则会退出循环,执行while语句后面的程序。

下面程序段的执行效果和上面的repeat程序段相同:

i := 0;

while i<10 do

begin

i := i+1;

writeln(i);

end;

在一个while循环中,建议不要使用exit语句来跳出循环,应尽量使用循环条件来跳出循环。

在一个while循环中所用的初始化代码应在进入while循环前出现,不要用其他不相关的语句把二者隔开。循环结束后的处理应在循环之后立即进行。

3)for语句

for语句也称循环语句,有两种格式。

格式1:

for 变量:=表达式1 to 表达式2 do 一段程序

格式2:

for 变量:=表达式1 downto 表达式2 do 一段程序

for语句的程序代码会执行一定的次数,它需要一个循环变量来控制循环次数,因此需要声明一个变量。它的类型可以是整数型、布尔型、字符型、枚举型或子界型。

下面的程序段会显示1~10的数字,其中i为控制变量。

var

i : integer;

for i := 1 to 10 do

writeln(i);

在循环次数已知的情况下,for语句能取代while语句。

1.4.4 过程与函数

如果一组语句能够完成某一功能,我们就把它定义为一个过程;如果要完成的功能是为了进行一系列处理之后返回一个值,那么就可以把它定义为一个函数。每一个过程或函数都以标题开始,其中包括过程或函数的名称和它使用的参数。过程以保留字procedure开始,函数以保留字function开始。

参数位于括号里面,多个参数之间以分号分隔,例如:

procedure SetDate(Year: Integer; Month: Integer; Day: Integer);

也可以将相同类型的参数组合在一起,则上述过程标题写成:

procedure SetDate(Year, Month, Day: Integer);

函数在标题中还多了一项——返回值的类型。下面是一个返回值为Double型的函数标题:

function GetAverage(num:integer;total:Double):Double;

1. 基本概念

(1)函数

定义函数的关键字是function。

函数有两类:一类是标准函数,这一类函数由Delphi定义并实现,程序员可以直接引用,应熟练掌握;另一类为自定义函数,要重点掌握它的声明和调用方法。一个自定义函数应首先在程序声明部分声明,之后才可以在程序的执行部分加以调用。

过程或函数的语句部分由begin开始、end结束。函数需要一个返回值。可以将返回值赋给函数名称,也可以将返回值赋给Result变量。

下面示例程序的作用是将返回值赋给函数名称:

function GetAverage(num:integer;total:Double):Double;

begin

GetAverage := total / num;

end;

也可以将返回值赋给Result变量,则上面程序中位于begin和end之间的语句改为:

Result := total / num;

(2)过程

定义过程的保留字是procedure。

过程也有两类:一类为Delphi定义的标准过程,另一类为自定义过程。

与函数不同,过程没有返回值。

2. 参数与作用域

(1)参数

过程和函数与外界的数据通信有两种方式:一种是通过全局量,另一种是通过参数。程序代码在调用一个过程或函数时,通常通过参数将数据传递到被调用的过程或函数中。最常用的参数有值参数、变量参数和常量参数3种。

· 值参数 若参数定义为值参数,则函数的调用对实参的值没有影响。

· 变量参数 若参数定义为变量参数,则函数调用的结果对实参的值有影响。

· 常量参数 如果参数定义为常量参数,则当过程或函数执行时不改变形参的值。

值参数与变量参数在定义上的区别在于:值参数在形式参数表中,只声明其数据类型;变量参数在形式参数表中需要以保留字var来声明。程序通过有无var来区别变量参数和值参数。常量参数利用const关键字来声明,在形式参数表的参数名称前加上保留字const可以使一个形参成为常量参数。

另外,由被调用过程或函数定义的参数称为形式参数,即形参;而由调用过程或函数引用的参数叫实际参数,即实参。例如,在函数定义和实现部分:GetAverage(num:integer; total:Double)中,num就是形式参数,而当我们调用这个函数:av:=GetAverage(n,ttl)时,其中n和ttl都是已经定义的变量,它们都是实际参数。

值参数在运行过程中只改变其形参的值,不改变其实参的值,即参数的值不能传递到过程的外面。如果想改变传入的参数值,就需要使用变量参数,即在被调用程序的参数表中的形参前加上保留字var。当一个变量参数被传递时,任何对形参所作的改变会反映到实参中,这是因为两个参数指向同一个地址。

如果当过程或函数执行时要求不改变形参的值,则最保险的办法是使用常量参数。在形式参数表的参数名称前加上保留字const可以使一个形参成为常量参数。使用常量参数代替数值参数可以保护用户的参数,使用户在不想改变参数值时不会意外地将新的值赋给这个参数。

(2)作用域

对于在程序中出现的变量,根据定义域的不同,拥有不同的作用域:

1)全局变量是在主程序中定义的变量。

2)局部变量是在过程或函数中定义的变量。

全局变量对于整个程序均适用,局部变量只对定义它的过程或函数有效。

Object Pascal语言对于变量的作用域有如下约定:

1)在不同层次可以定义使用同名变量,但在同一层中1个变量只能定义1次。

2)同名变量在不同层次被定义时,代表不同的对象。执行内层程序时,外层的非局部变量虽然存在,却已经被屏蔽;而当程序从内层退出后,内层的局部变量就已经不存在,只有外层的那个非局部变量仍然存在。

1.4.5 类与对象

从用户角度考虑,用户并不需要了解面向对象编程的知识,就可编写Delphi应用程序。当用户在建立新窗体、添加新组件以及处理事件时,大部分相关代码会由Delphi自动产生。但是,知道语言及其细节,对理解Delphi正在做什么并完全掌握它是很有帮助的。特别是有关类的概念及用法是后面学习组件编程以及Delphi深入编程的基础。

类和对象是两个常用的术语,然而经常容易混淆,因此须要区分它们的定义。

1. 类

类与前面介绍的记录类似,也是包含有各种域的结构化数据类型,然而,类包含方法。方法就是操纵对象域数据的过程或函数。类类型把数据和方法封装在一起。

一个类是一个数据类型。类就像记录一样,是一种数据结构。按最简单的理解,可以将类理解成一个记录。但实际上,类是一种定义不确切的术语,它常用来定义抽象的事务,是构成应用程序的项目,其内涵远比记录要丰富。在本书中,类经常可以被理解为可视化组件,如按钮、标签、表等。

了解类,最关键的是掌握类的特性。一个类,其最突出的特征有3个:封装性、继承性、多态性。

(1)封装性

对类最基本的理解是,类把数据和代码组合在同一个结构中,这就是类的封装性。将类的数据域封闭在类的内部,使得外部程序必须使用正确的方法才能对要读写的数据域进行访问。封装性意味着数据和代码一起出现在同一结构中,只有用类的方法才能接触到内部的私有数据。

(2)继承性

继承性的含义直接而且显然,它是指把一个新的类定义成已存在类的后代。新类通过继承得到了旧类的一切东西。在往新类中添加任何新内容以前,父类的每一个属性和方法都已存在于子类中,父类是创建子类的基石。

(3)多态性

多态性是在类体系中把设想和实现分开的手段。如果说继承性是系统的布局手段,那么多态性就是实现其功能的方法。多态性意味着同样的动作可以由多种方式来实现,这取决于执行该动作的类。多态性允许以类似的方式处理类体系中类似的类。根据特定的任务,一个应用程序被分解成许多类,多态性把高级设计处理的设想,如新类的创建、类在屏幕上的显示、程序运行的其他抽象描述等,留给知道该如何处理它们的类去实现。

在Object Pascal中,声明类类型使用保留字Class。类类型可以指定一个祖先类型,表示该类型是从这个指定的祖先类型继承下来的,例如:

Type

TMyObject=Class(TObject)

上例声明了一个名叫TMyObject的类类型,该类型是从类 TObject继承下来的。注意,类类型的标识符一般以“T”打头,以区别于其他数据类型。另外,在Delphi中,大量的构造数据类型都是以“T”打头的。如果不指明祖先类,Delphi默认该类继承自TObject类。

2. 对象

对象是类的实例(instance),即由类定义的数据类型的变量。对象是实体,当程序运行时,对象占用一些内存。对象与类的关系就像变量与类型的关系。

例如,针对上文声明的类TMyObject,可以声明它的一个实例:

var

Aobject : TMyObject;

然后通过Aobject.属性或Aobject.方法就可以实现对这个对象的属性或方法的访问。

其中下标类型应该是顺序类型。枚举类型是顺序型。

但当两个数组变量的类型相同时,允许以变量名整体地互相赋值。

数组的下标类型部分可以省略,这就是一个长度可变的数组(动态数组)

type 集合型=set of 基类型;

可以用5种关系运算符=、< >、<=、>=和in来测试集合成员关系。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics