一、
1.类成员的可见性
- private //不可见
- protected //派生类可见
- public //可见
- published //可见。用于运行时信息
- automated //可见。用于兼容(只用于windows)
在{$M+}状态下编译类时,它的默认可见性为published;否则,则它的可见性是public;
2.类方法调用
inherited(继承):就是调用父类的函数。如果不带参数就是默认调用父类的同名函数;如果带参数则表明子类中的函数的参数个数可能比祖先类要多取其中的几个参数传过去
例如
- 祖先类有个函数 Create(AName:string);
- 子类有个函数 Create(AName:string;AComponent:TObject);override;
- 那么子类的Create函数内就可以这样调用祖先类:
- procedure TAClass.Create(AName:string;AComponent:TObject);
- begin
- Inherited Create(AName);
- end;
类方法可以看做是公共方法,对于类方法的调用。例如:
- 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.覆盖虚方法
- //定义父类、子类方法
- {父类}
- 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;
实现类的方法、过程
- {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.抽象类考虑到抽象类在某种程度上可以用接口来代替,所以这里我并不在仔细对抽象类进行介绍。直接给例子:
- {父类}
- TParent = class
- protected
- function MyFun(i:Integer):Integer;abstract; //动态方法
- end;
- {子类}
- TChild = class(TParent) //继承父类
- protected
- function MyFun(i:Integer):Integer;override; //覆盖方法
- end;
对类方法的实现也和第3点类方法的覆盖相类似。
5.方法重载
- {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.参数默认值
例如
- //带默认值的参数只能在后面
- function MyFun(a:Integer; b:Integer=1; c:Integer=2): Integer;
- begin
- Result := a + b + c;
- end;
如在调用该函数时,对参数已赋值。则默认值不起作用;如未赋值,则用默认值进行操作。
7.属性的自动完成
在Type区写入
- TMyClass = class
- property s: string;
- end;
然后把光标放在其中,执行Ctrl+Shift+C。Delphi会自动生成属性的相关代码
- 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的调用(可读性好):
- type TMyClass = class(TObject)
- ...
- end;
9.Forward声明
- type
- TFigure = class;
- TDrawing = class
- Figure : TFigure;
- ...
- end;
- TFigure = class
- Drawing: TDrawing;
- ...
- end;
二、
1.结构与类都是自定义类型,结构可以直接使用,内存是自动管理;类对象需要创建才可以使用,并在使用完成后需要对其手动释放。例如
- 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.关于类的属性
类属性的定义:
- {定义两个属性}
- 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方法:
- 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;
设置属性的直
- myClass2.Age := 99; //访问属性
4.类与事件
关于类与事件的定义,我将通过一个例子来给予说明。
事件的定义:
- //定义事件
- 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一开始创建的时候就必须先定义一个事件。
- constructor TMyClass.create;
- begin
- FOnHundred:= SetOnHundred1;
- end;
事件的调用
- myclass.OnHundred := myclass.SetOnHundred2; //事件的指定(类似于属性)
事件类型是一个指针,指向一个过程(不带返回值的方法),事件在定义时指定了参数的类型和个数,调用过程的参数必须与其保持一致。
5. 字段
- 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.类的继承
继承类的定义
- {父类}
- TBase = class
- procedure msg1;
- end;
- {继承父类}
- TChild = class(TBase)
- procedure msg2;
- end;
对于子类与父类的使用与一般类的调用并没有特殊的区别,这里不再详述。在子类中,如果需要调用父类的方法,可以利用inherited指示字:
- procedure TChild1.Proc;
- begin
- inherited Proc; {调用父类的 Proc 方法}
- end;
2.类的封装
待补充。。。
3.类的多态性
多态是同一个方法在不同的对象里会有不同的实现。在定义类的多态的时候需要在父类创建虚方法,并在子类重写该方法。
- {父类}
- TBase = class
- procedure alert;virtual; //定义一个虚方法
- end;
- {子类1}
- TChild1 = class(TBase)
- procedure alert;override; //重载父类方法
- end;
- {子类2}
- TChild2 = class(TBase)
- procedure alert;override;
- end;
以下是对于类的调用
- {调用父类的方法}
- 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说明抽象类,但内部必须有抽象方法。例如
- TMyClass5 = class abstract(TObject)
- procedure Proc; virtual; abstract;
- end;
类中数据成员的排列顺序一般是:字段、方法、属性。
5.类的向前声明
例如:
- //解决方案 - 向前声明
- TClassB = class; {向前声明}
- TClassA = class
- Field1: string;
- Field2: Integer;
- Field3: TClassB;
- end;
- TClassB = class
- Field1: string;
- Field2: Integer;
- end;
1.类的方法参数可以分为四种(默认参数(传值)、var(传址)、out(输出)、const(常数))。这里需要注意的是var定义的参数,例如:
- {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.在类中的方法
如果一个方法被声明在一个类中,那么调用该方法前就必须先对该类进行初始化。这与其他语言对于类中方法的调用是一致的;并且在实现该方法时,必须在方法名前加上类的前缀,例如:
- {函数在实现区必须有 TForm1. 作为前缀}
- function TForm1.MyFun(x,y: Integer): Integer;
- begin
- Result := x + y;
- end;
4.调用其他单元的函数
在调用其他单元的函数时,被调用单元的函数必须在interface区中声明,并在implementation区中也实现。在调用时,我们需要对其单元进行引用,例如:
- 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指示字。例如:
- 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区把数组定义成一个类型,在对该类型定义一个变量,最后在使用该变量。例如:
- //应该先把数组定义成一个类型
- 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区将其定义为一个类型。例如:
- function MyFun(const arr: array of Integer): Integer;
对于遍历开放数组也需要注意,因不知其长度,所以在遍历时需要用到Low()和High()方法,例如:
- for i := Low(iArr) to High(iArr) do
- begin
- iArr[i] := i + 1;
- end;
7.指针参数
在方法中传递指针,我们需要用指针类型来定义。具体实现如下:
- function MyFun(p: PInteger): Integer; {PInteger 是 Integer 的指针类型}
- begin
- p^ := p^ * 2;
- Result := p^;
- end;
在调用该函数时,需要用@来获取变量的地址,例如:
- var
- i,x: Integer;
- begin
- i := 8;
- x := MyFun(@i);
9.方法重载
方法的重载只要用在方法重名但参数不一样的情况,在方法后面必须声明overload指示字。在调用时根据参数来决定调用哪个方法。这与其他语言的重载相似。在published区中的方法命名要有唯一性,该区域方法不能被重载。