深入理解Delphi中类属性的用法
关于属性的话题还有很多, 譬如: 数组属性、默认属性、class 属性等等.
先总结一下前面提到过的属性吧.
TMyClass = class(TObject)
private
FName: string;
procedure SetName(const Value: string);
published
property Name: string read FName write SetName;
end;
1、属性用 property 定义;
2、read、write 两个关键字至少要存在一个, 如果只有一个就成了只读属性或只写属 性;
3、属性名后面也要指定类型(必须是内置类型或定义在前面的类型), 存取的类型必须 要和它一致;
4、属性用到的字段与方法一定要声明在属性前面;
5、如果属性读(read)的是方法, 那么这个方法一定是个函数, 且返回值与属性类型一 致;
如果属性是非数组属性, 该函数是无参数的, 譬如: function GetName: string;
6、如果属性写(write)的是方法(一般也不会是字段), 那么这个方法一定是个过 程;
如果属性是非数组属性, 该过程必须只有一个参数, 参数类型必须和属性一致; 并且 参数必须是传值的;
譬如: procedure SetName(s: string); 或者 procedure SetName(const s: string);
7、属性调用的方法不能是虚方法或动态方法; 不能是重载方法;
8、如果属性在 published 区, 那它调用的方法只能使用默认的 register 调用约 定;
9、属性一般放在 published 区, 如果属性不是公开的也就失去了属性的意义;
10、如果自定义的类不需要 RTTI 或许把属性放到 public 区会更节省(个人认 为);
11、属性读写的变量或方法一般放在 private 区, 如果都公开了就用不着属性 了;
12、事件属性读写的必须是方法, 不能是变量;
13、属性只是一个桥, 它没有指针(它读写的变量和方法才有指针), 目的是方便存取 并提出存取限制;
14、还有 Delphi 的 IDE 为书写属性提供了非常方便的快捷键, 譬如:
输入: property Name: string; 然后执行 Ctrl+Shift+C ...
案例:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
//TMyClass1 类里面只有两个字段(变量来到类里面称做字段)
TMyClass1 = class
FName: string; {字段命名一般用 F 开头, 应该是取 field 的首字母}
FAge: Integer; {另外: 类的字段必须在方法和属性前面}
end;
{这个类中的两个字段, 可以随便读写; 在实际运用中, 这种情况是不存在的.}
//TMyClass2 类里面包含两个属性(property)、两个方法、两个和 TMyClass1 相同的字段
TMyClass2 = class
strict private
FName: string;
FAge: Integer;
procedure SetAge(const Value: Integer);
procedure SetName(const Value: string);
published
property Name: string read FName write SetName;
property Age: Integer read FAge write SetAge;
end;
{
但这里的字段: FName、FAge 和方法: SetAge、SetName 是不能随便访问的,
因为, 它们在 strict private 区内, 被封装了, 封装后只能在类内部使用.
属性里面有三个要素:
1、指定数据类型: 譬如 Age 属性是 Integer 类型;
2、如何读取: 譬如读取 Age 属性时, 实际上读取的是 FAge 字段;
3、如何写入: 譬如希尔 Age 属性时, 实际上是通过 SetAge 方法.
属性不过是一个桥.
通过属性存取字段 和 直接存取字段有什么区别?
通过属性可以给存取一定的限制,
譬如: 一个人的 age 不可能超过 200 岁, 也不会是负数; 一个人的名字也不应该是空值.
看 implementation 区 TMyClass2 类的两个方法的实现, 就增加了这种限制.
}
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TMyClass2 }
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;
//测试:
procedure TForm1.Button1Click(Sender: TObject);
var
class1: TMyClass1;
class2: TMyClass2;
begin
class1 := TMyClass1.Create;
class2 := TMyClass2.Create;
class1.FAge := 1000; {TMyClass1 中的 FAge 字段可以接受一个离奇的年龄}
class2.Age := 99; {通过 TMyClass2 中的 Age 属性, 只能赋一个合理的值}
//class2.FAge := 99; {TMyClass2 中的 FAge 字段被封装了, 在这里无法使用}
class1.Free;
class2.Free;
end;
end.
网友评论