您的位置:首页 > 编程语言 > Delphi

Delphi的学习笔记十一——类

2016-05-28 06:27 507 查看
一、

1.类成员的可见性

[delphi] view
plaincopy

private //不可见

protected //派生类可见

public //可见

published //可见。用于运行时信息

automated //可见。用于兼容(只用于windows)

在{$M+}状态下编译类时,它的默认可见性为published;否则,则它的可见性是public;

2.类方法调用

inherited(继承):就是调用父类的函数。如果不带参数就是默认调用父类的同名函数;如果带参数则表明子类中的函数的参数个数可能比祖先类要多取其中的几个参数传过去

例如

[delphi] view
plaincopy

祖先类有个函数 Create(AName:string);

子类有个函数 Create(AName:string;AComponent:TObject);override;

那么子类的Create函数内就可以这样调用祖先类:

procedure TAClass.Create(AName:string;AComponent:TObject);

begin

Inherited Create(AName);

end;

类方法可以看做是公共方法,对于类方法的调用。例如:

[delphi] view
plaincopy

constructor TMyClass.Create;

begin

inherited;

MyProc; //调用类方法

end;

class procedure TMyClass.MyProc;

begin

ShowMessage('OK'); //类方法实现

end;

procedure TForm1.FormCreate(Sender: TObject);

var

myclass : TMyClass;

begin

TMyClass.MyProc; //用类名调用类方法

myclass := TMyClass.Create; //初始化对象

myclass.MyProc; //对象调用类方法

myclass.Free; //释放对象

end;

3.覆盖虚方法

[delphi] view
plaincopy

//定义父类、子类方法

{父类}

TParent = class

protected

function MyFun(i:Integer):Integer;dynamic; //动态方法

procedure MyProc; virtual; //虚方法

end;

{子类}

TChild = class(TParent) //继承父类

protected

function MyFun(i:Integer):Integer;override; //覆盖方法

procedure MyProc; override;

end;

实现类的方法、过程

[delphi] view
plaincopy

{TParent}

function TParent.MyFun(i:Integer): Integer;

begin

Inc(i); //i++

Result:=i; //返回变量i

end;

procedure TParent.MyProc;

begin

ShowMessage('Parent');

end;

{TChild}

function TChild.MyFun(i:Integer):Integer;

begin

i:= inherited MyFun(i); //继承父类的MyFun方法

Inc(i);

Result:=i;

end;

procedure TChild.MyProc;

begin

inherited; //调用父类的MyProc方法

ShowMessage('child');

end;

我们可以注意到在实现子类方法的时候利用inherited来继承父类的方法。

4.抽象类考虑到抽象类在某种程度上可以用接口来代替,所以这里我并不在仔细对抽象类进行介绍。直接给例子:

[delphi] view
plaincopy

{父类}

TParent = class

protected

function MyFun(i:Integer):Integer;abstract; //动态方法

end;

{子类}

TChild = class(TParent) //继承父类

protected

function MyFun(i:Integer):Integer;override; //覆盖方法

end;

对类方法的实现也和第3点类方法的覆盖相类似。

5.方法重载

[delphi] view
plaincopy

{1.关于方法重载:

2.过程和函数之间可以重载

3.类内重载必须有 overload 关键字

4.子类重载必须有 overload 关键字,夫类可以没有

5.如果夫类是虚函数(virtual dynamic),子类重载时需要加 reintroduce 修饰词

6.published 区内不能重载}

//方法重载

TMyClass2 = class

protected

procedure MyProc1(i:Integer); overload; //重载方法

function MyFun1(s1,s2:string): string; overload;

end;

对类方法的实现也和第3点类方法的覆盖相类似。

6.参数默认值

例如

[delphi] view
plaincopy

//带默认值的参数只能在后面

function MyFun(a:Integer; b:Integer=1; c:Integer=2): Integer;

begin

Result := a + b + c;

end;

如在调用该函数时,对参数已赋值。则默认值不起作用;如未赋值,则用默认值进行操作。

7.属性的自动完成

在Type区写入

[delphi] view
plaincopy

TMyClass = class

property s: string;

end;

然后把光标放在其中,执行Ctrl+Shift+C。Delphi会自动生成属性的相关代码

[delphi] view
plaincopy

TMyClass = class

private

Fs: string;

procedure Sets(const Value: string);

published

property s: string read Fs write Sets;

end;

{ TMyClass }

procedure TMyClass.Sets(const Value: string);

begin

Fs := Value;

end;

8. 对TClass的调用(可读性好):

[delphi] view
plaincopy

type TMyClass = class(TObject)

...

end;

9.Forward声明

[delphi] view
plaincopy

type

TFigure = class;

TDrawing = class

Figure : TFigure;

...

end;

TFigure = class

Drawing: TDrawing;

...

end;

二、

1.结构与类都是自定义类型,结构可以直接使用,内存是自动管理;类对象需要创建才可以使用,并在使用完成后需要对其手动释放。例如

[delphi] view
plaincopy

type

TMyRecord = Record

d:TDate;

end;

TMyClass = class

d:TDate;

end;

procedure TForm2.Button1Click(Sender: TObject);

var

myRecord : TMyRecord;

myClass : TMyClass;

begin

//使用结构(不需要初始化,内存自动管理)

myRecord.d := Now;

ShowMessage(DateToStr(myRecord.d));

ShowMessage(IntToStr(SizeOf(myRecord)));//8

//使用类

myClass := TMyClass.Create; //初始化对象

myClass.d := Now;

ShowMessage(DateToStr(myClass.d));

ShowMessage(IntToStr(SizeOf(myClass)));//4

myClass.Free; //释放对象

end;

2.关于类的方法,在上一篇类的的文章中已经有所涉及。这里就不再详述。一般情况下,类都会定义在interface区;在implementation区定义的类只能本单元使用。

3.关于类的属性

类属性的定义:

[delphi] view
plaincopy

{定义两个属性}

TMyClass2 = class

private

FName : string;

FAge : Integer;

procedure SetAge(const Value:Integer); //Value设置为常量

procedure SetName(const Value:string);

published

property Name: string read FName write SetName;

property Age : Integer read FAge write SetAge;

end;

自定义set方法:

[delphi] view
plaincopy

procedure TMyClass2.SetAge(const Value: Integer);

begin

if (Value>=0) and (Value<200) then

FAge := Value;

end;

procedure TMyClass2.SetName(const Value: string);

begin

if Value<>'' THEN

FName:= Value;

end;

设置属性的直

[delphi] view
plaincopy

myClass2.Age := 99; //访问属性

4.类与事件

关于类与事件的定义,我将通过一个例子来给予说明。

事件的定义:

[delphi] view
plaincopy

//定义事件

TMyEvent = procedure of object;

TMyClass = class

private

FAge:Integer;

FOnHundred:TMyEvent;

procedure SetAge(const Value:Integer);

published

procedure SetOnHundred1; //定义事件1

procedure SetOnHundred2; //定义事件2

constructor create; //Form初始化时执行

property Age:Integer read FAge write SetAge;

property OnHundred: TMyEvent read FOnHundred write FOnHundred; //定义事件属性(通过属性的形式来设置事件)

end;

在Form一开始创建的时候就必须先定义一个事件。

[delphi] view
plaincopy

constructor TMyClass.create;

begin

FOnHundred:= SetOnHundred1;

end;

事件的调用

[delphi] view
plaincopy

myclass.OnHundred := myclass.SetOnHundred2; //事件的指定(类似于属性)

事件类型是一个指针,指向一个过程(不带返回值的方法),事件在定义时指定了参数的类型和个数,调用过程的参数必须与其保持一致。

5. 字段

[delphi] view
plaincopy

type

TAncestor = class

Value : Integer;

end;

TDescendant = class(TAncestor)

Value : string;

end;

var

MyObject : TAncestor;

begin

MyObject := TDescendant.Create;

TDescendant(MyObject).Value := 'hello world';

end;

三、

1.类的继承

继承类的定义

[delphi] view
plaincopy

{父类}

TBase = class

procedure msg1;

end;

{继承父类}

TChild = class(TBase)

procedure msg2;

end;

对于子类与父类的使用与一般类的调用并没有特殊的区别,这里不再详述。在子类中,如果需要调用父类的方法,可以利用inherited指示字:

[delphi] view
plaincopy

procedure TChild1.Proc;

begin

inherited Proc; {调用父类的 Proc 方法}

end;

2.类的封装

待补充。。。

3.类的多态性

多态是同一个方法在不同的对象里会有不同的实现。在定义类的多态的时候需要在父类创建虚方法,并在子类重写该方法。

[delphi] view
plaincopy

{父类}

TBase = class

procedure alert;virtual; //定义一个虚方法

end;

{子类1}

TChild1 = class(TBase)

procedure alert;override; //重载父类方法

end;

{子类2}

TChild2 = class(TBase)

procedure alert;override;

end;

以下是对于类的调用

[delphi] view
plaincopy

{调用父类的方法}

procedure TForm2.Button1Click(Sender: TObject);

var

base : TBase;

begin

base := TBase.Create;

base.alert;

base.Free;

end;

{调用子类1的方法}

procedure TForm2.Button2Click(Sender: TObject);

var

base : TBase;

begin

base := TChild1.Create;

base.alert;

base.Free;

end;

这里我们可以看到,对父类对象引用子类对象进行初始化,这也充分体现了类的多态性。

4.抽象类

用class abstract说明抽象类,但内部必须有抽象方法。例如

[delphi] view
plaincopy

TMyClass5 = class abstract(TObject)

procedure Proc; virtual; abstract;

end;

类中数据成员的排列顺序一般是:字段、方法、属性。

5.类的向前声明

例如:

[delphi] view
plaincopy

//解决方案 - 向前声明

TClassB = class; {向前声明}

TClassA = class

Field1: string;

Field2: Integer;

Field3: TClassB;

end;

TClassB = class

Field1: string;

Field2: Integer;

end;

四、

1.类的方法参数可以分为四种(默认参数(传值)、var(传址)、out(输出)、const(常数))。这里需要注意的是var定义的参数,例如:

[delphi] view
plaincopy

{var参数是传址, 会被改变}

function MyF2(var x: Integer): Integer;

begin

Inc(x);

Result := x;

end;

Inc(x):表示对x的内存地址加1,这将导致方法返回的值的变化。

对于out(输出),其用法和var一致,所以在一般情况下我们采用var来定义而不是out;对于const,则表示该定义的变量为常量,常量的值无法改变。

2.implementation区/interface区的方法

对于implementation区中的方法,只能在本单元中调用。这里就不举例子了,在之前的举例中都有涉及。

对于interface区中的方法,可以被其它单元调用。

3.在类中的方法

如果一个方法被声明在一个类中,那么调用该方法前就必须先对该类进行初始化。这与其他语言对于类中方法的调用是一致的;并且在实现该方法时,必须在方法名前加上类的前缀,例如:

[delphi] view
plaincopy

{函数在实现区必须有 TForm1. 作为前缀}

function TForm1.MyFun(x,y: Integer): Integer;

begin

Result := x + y;

end;

4.调用其他单元的函数

在调用其他单元的函数时,被调用单元的函数必须在interface区中声明,并在implementation区中也实现。在调用时,我们需要对其单元进行引用,例如:

[delphi] view
plaincopy

implementation

{$R *.dfm}

uses Unit2; {必须 uses 定义函数的单元}

procedure TForm1.Button1Click(Sender: TObject);

var

i: Integer;

begin

i := MyFun(1,2); {调用函数}

//i := Unit2.MyFun(1,2); {有时为了避免重名, 需要这样调用}

ShowMessage(IntToStr(i)); {3}

end;

5.方法的提前声明

如果前面的方法需要调用后面的方法,则需要在被调用的方法中声明forward指示字。例如:

[delphi] view
plaincopy

function MyFunB(x: Integer): Integer; forward; {使用 forward 指示字提前声明}

function MyFunA(x: Integer): Integer;

begin

Result := MyFunB(x) * 3; {要调用后面的方法, 后面的方法需要提前声明}

end;

function MyFunB(x: Integer): Integer;

begin

Result := Abs(x);

end;

但如果该方法已在interface区中提前声明了,那么就无需在对方法添加forward指示字了。

6.静态数组做参数

对于静态数组做参数,我们需要在Type区把数组定义成一个类型,在对该类型定义一个变量,最后在使用该变量。例如:

[delphi] view
plaincopy

//应该先把数组定义成一个类型

Type

IntArray = array[0..9] of Integer; {先把需要的数组定义成一个类型}

//给一个静态数组求和的函数

function MyFun(arr: IntArray): Integer;

var

i: Integer;

begin

Result := 0;

for I:= 0 to Length(arr)-1 do

begin

Result := Result + arr[I];

end;

end;

而对于开放数组参数,则可以将其直接作为参数来使用,不需要在Type区将其定义为一个类型。例如:

[delphi] view
plaincopy

function MyFun(const arr: array of Integer): Integer;

对于遍历开放数组也需要注意,因不知其长度,所以在遍历时需要用到Low()和High()方法,例如:

[delphi] view
plaincopy

for i := Low(iArr) to High(iArr) do

begin

iArr[i] := i + 1;

end;

7.指针参数

在方法中传递指针,我们需要用指针类型来定义。具体实现如下:

[delphi] view
plaincopy

function MyFun(p: PInteger): Integer; {PInteger 是 Integer 的指针类型}

begin

p^ := p^ * 2;

Result := p^;

end;

在调用该函数时,需要用@来获取变量的地址,例如:

[delphi] view
plaincopy

var

i,x: Integer;

begin

i := 8;

x := MyFun(@i);

9.方法重载

方法的重载只要用在方法重名但参数不一样的情况,在方法后面必须声明overload指示字。在调用时根据参数来决定调用哪个方法。这与其他语言的重载相似。在published区中的方法命名要有唯一性,该区域方法不能被重载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: