一、类和对象
1、基本概念
客观世界中,可以把具有相似特征的事物归为一类,具有相同属性的对象看成一个类(class),如所有的汽车看成“汽车类”,类就是对具有相同属性和相同操作的一组对象的定义。
对象是类的实例,每一个有明确意义和边界的事物都可以看成一个对象。对象的固有性质是含有域和方法。如我们在对象中加入一个按钮,则在代码中就显示了这个按钮的代码也就是域。
2、类的声明
类是一个构造函数,由属性和方法构成,其中属性又包含类的内部属性和外部属性,也就是供内部使用的数据和供外部使用的数据变量。方法则是该类或其实例可以操作的过程和函数。通常把类的内部属性称为字段,把字段、属性和方法统称为类的成员。
类的声明如下
type ClassName=class(AncestorClass)
MemberList
end;
//AncestorClass是类继承父类的名称。
真正的类还包括类的成员和方法,下面的类包含了类的成员和方法。
type
TPerson=class
Name:string; 类的成员
age:Integer;
function getage(n:string):integer;
end;
end;
2、创建对象
从根本上讲对象是一个类的实例,是一块动态分配的内存块,其结构由类定义。对象通过构造函数创建,析构函数删除。
当创建一个类时,调用大类的构造方法create来分配内存空间,这个方法是每一个class都具有的隐含的方法。类类型必须使用create方法创建,其它类型声明后即可直接使用。
声明一个TEngineer类型的变量:
var
ThisMan:TEngineer;
ThisMan:=TEngineer.Create;
ThisMan只是一个指针,并不能说它是一个对象,为了创建一个对象,应该调用它的create方法,ThisMan:=TEngineer.Create;
构造函数必须由对象引用调用,即类变量来调用此函数。
create是一个特殊方法,是Constructor(构造器)
3、消灭对象(析构函数)
析构函数取消对象并释放内存,也必须由对象引用调用,即用类变量来调用此函数。
析构函数的关键字是destructor,
destructor TPerson.Destroy;
begin
TPerson.free;
end;
但在实际情况中,释放对象的函数有两种:destroy 和free,建议用free,因为它比destroy更安全,且生成效率更高的代码,下面是free方法的代码。
procedure TObject.Free;
begin
if Self<>nil then
Destroy;
end;
可以看出,free方法先检验对象是否已经被撤销,如果没有被撤销,那么调用Destroy函数,否则什么也不做。
二、属性、方法和事件
1、属性:可以把属性看成能对类中的数据进行修改和执行代码的特殊辅助域。对于组件来说,属性就是列在object inspector窗口的内容。属性拥有两个类似于函数的块,一个块用于获取属性的值,另一个块用于设置属性的值。这两个块也称为存取程序,分别用read和write关键字来义,可用来控制对属性的范文级别。
属性也表示操作类里数据域的间接层,是我们访问对象里数据的一个接口,对类里面的数据实施保护,类里面的数据对外面是隐藏的。通过属性成员就可以控制外界对数据成员的访问。一般情况下,属性的访问性是public(或者访问性为Protected),用于外部代码的调用。
声明属性需要的关键字property,一般格式为:
property 属性名:属性类型 read 变量或者方法名称 write 变量或者方法名称 default 默认值;
//变量的名称前加上一个大写F
//方法的时候,用get命名,写用set命名 如SetDataReal
1)直接操作数据成员的变量
type
TMyClass=class
publicshed//公共的访问修饰
property datareal:Real read FDataReal write FDataReal; //通过公共的属
性操作私有的数据成员
private
FDataReal:Real; //私有的数据成员
end;
2)我们不想直接操作数据成员的变量,使用方法对这个字段进行判断、检查、计算。
type
TMyClass=class
publicshed//公共的访问修饰
property datareal:Real read GetFDataReal write SetDataReal; //通过调
用操作私有的数据成员
private
FDataReal:Real; //私有的数据成员
procedure SetDataReal(const Value:Real); //声明一个方法,括号内的为传过
来数据的类型。
end;
implementation //执行部分
procedure TMClass.SetDataReal(const Value:Real);
begin
FDataReal:=Value; 把传进来的值存起来,存给FDataReal这个变量。
end;
但我们用赋值时如,a.DataReal:=3时,调用了SetDataReal,从而调用了procedure SetDataReal(const Value:Real);把值传进来后就存入了FDataReal字段里。
当我们打印输出时,直接用a.DataReal。
2、方法
方法是类的重要成员,方法是属于一个给定对象的过程和函数,方法反映的是对象的行为而不是数据,方法实际就是写在类里面的函数或过程,方法是跟类和对紧密联系在一起的,与普通的过程或函数还是 有主要的区别,区别如下:
1、方法的前向分类,方法的前面要加上类名限定符。加类名。
2、方法的后向分类,方法添加一些已有的指示字或保留字
3、seff变量及其使用,
1)方法的类型
方法按指示字分为4种,分别是静态方法、虚拟方法、动态和消息方法,它们又分别由方法名后的static,virtual,dynamic,message保留字指定,不加方法的指示字默认为静态(static)
type
TMember = class
procedure SetStatic; //静态方法
procedure SetVirtual;virtual; //是虚拟方法;
procedure SetDynamic; dynamic;//动态方法
procedure SetMessage(var M:TMessage); message WM_SomeMessage; //消息方法
end;
还有一种附加的指示字abstract,表示方法是抽象的。
type
procedure SomeProcedure virtual; abstract;
①静态方法
编译器在编译时就已经指定了输出该方法的对象实例。静态方法的主要优点就是调用速度快。当从一个类派生一个子类时,静态方法不会改变,当派生一个静态方法的新类,则被派生的类在同一地址共享基类的静态方法。
②虚拟方法
虚拟方法不是在编译时确定的,而是在程序运行时间根据调用这个虚拟方法的对象实例来确定的,这种方法称为滞后联编。虚拟方法在对象的虚拟方法表中(VMT表)中占有一个索引号。
VMT表保存类类型的所有虚拟方法的地址。当从一个类派生新类时,派生类会创建它自己的VMT,该VMT包括了基类的VMT,同时加上自己定义的虚拟方法的地址。
③动态方法
非常类似虚拟方法,派生类可以重载它。与虚拟方法不同的是被声明的动态的方法不是放在类的虚拟方法表中,而是由编译器给它一个索引号,调用动态方法时,由索引号决定调用哪一个该方法的具体实现(即从重载的方法中选择哪一个来执行)。
虚拟方法调用速度快,但其代码较长,类型对象占用的空间大;而动态方法调用速度慢,但对象占用空间小,如果一个方法经常调用,或该方法要求执行的时间短,则最好选择使用虚拟方法。
④消息方法
在方法定义时加上一个message指示字,就可以定义一个消息处理程序方法。消息处理成立程序方法主要用于响应并处理某个特定的事件。
type
TMyButton=class(TCustomControl)
private
procedure WMChar(var Message:TWMchar); message WMCHAR;
end;
代码解释:
声明了一个叫TmyButton类类型,声明了一个过程WMChar,只有一个变量参数Message,过程声明后面用保留字message表示这是个消息处理程序,然后跟一个常量WMChar表示消息处理程序要响应的windows消息。
⑤抽象方法
在方法的调用约定之后加上一个abstrace,就可以进一步指明该方法是否是抽象的。所谓抽象方法首先必须是虚拟或动态的,其次在它所在类只能声明而不能定义,只能在派生类中定义它(重载)。因此定义一个抽象方法,只是定义它的接口,而不是定义底层的操作。
procedure Draw;Virtual;abstract;
2)方法的重载
用方法的重载实现OOP的多态性概念。通过重载使方法在不同的派生类间表现出不同的行为。能被重载的方法是在声明时被标识为virtual或dynamic的方法。为了重载一个方法,在派生类中声明中用override替代virtual或dynamic.
type
TMyClass = class
procedure A;virtual;
end;
type
TNewClass=class(TMyClass)
procedure A;override;
end;
procedure TMyclass.A;
begin
showmessage(调用了TMyclass的方法’);
end;
procedure TMyclass.A;
begin
inherited;
showmessage(调用了TMyclass的方法’);
end;
inherited:是继承的意思,它的功能是调用基类中相应的虚拟方法中的代码。如果不加inherited,基类的方法将被覆盖。
inspector:检查员; 视察员; 巡视员; (警察) 巡官; (英国公共汽车或火车上的) 查票员