property WindowState: TWindowState read FWindowState write SetWindowState;

{声明一个属性WindowState,它从字段FWindowState读取值,用方法SetWindowState保存值(方法SetWindowState在内部将值保存到字段FWindowState)}

property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy

{声明一个特殊的属性——事件OnDestroy,和上面的不同,OnDestroy的存取都是通过字段FOnDestroy进行的}

==================================

如果类的定义和类的使用者在同一个单元内,那么该类的所有成员无论位于哪个区域,对于使用者而言都是可见的。 一个类对于相同单元的其他类来说,类似于C++中的“友类”,其所有成员都可以被访问。因此,类成 员的可见性设置只是在它们位于不同单元时,才是有效的。这时候,区域内成员的可见性规定如下:

(1) private 域:总不可见。这个区域用来隐藏一些实现细节并防止使用者直接修改敏感信息,比如 容纳属性的存取字段和方法。 (2) protected:派生类可见。这样既可以起到private 域的作用,也能给派生类提供较大的灵活性。 该区域常被用来定义虚方法。 (3) public:总可见。通常用来放置构造、析构函数等供使用者调用的方法。 (4) published:总可见。而且这个区域的类成员有运行时类型信息,该区域通常用来放置供使用者 访问的属性和事件。 (5) automated:总可见。而且该域的成员具有自动化类型信息,用于创建自动化服务器。该关键字 已经不再使用,为向后兼容保留。

=====================================

我们发现字段Button1 和过程Button1Click 并没有被明确地放到哪个可见性区域中。那么这时候 它们的可见性按什么规则来确定呢?此时和编译指令$M 密切相关。 后面我们要讲:$M 用来控制编译器是否给类生成运行时类型信息。所以,在{$M+}状态,Button1 和Button1Click 被隐含指定到published 域;在{$M-}状态,则到public 域。 那么对于上面的TForm1 来说,因为它现在处在{$M+}状态,所以Button1 和Button1Click 实际上 被隐含指定到published 域。

=================================

从调用者角度可分为: ① 普通方法; ② 类方法。 普通方法只能被类实例(即对象)调用,而类方法不但可以被对象调用,还可以直接被类调用(比 如构造函数Create 和析构函数Destroy)。

。实现一个类方法时,要特别注意不要让它依赖 于任何实例信息,千万不要在类方法中存取字段、属性和普通方法。否则通过类而不是对象来调用它 时,将发生错误,因为此时并没有实例信息。

===================================

inherited 并不仅仅局限在子类覆盖后的虚方法中调用父类中被覆盖的方法,实际上,inherited 可以使用在任何地方、调用子类可见的任何父类方法(包括protected、public、published 等域的)。

===================================

③ 抽象方法。它是虚方法的特例,在虚方法声明后加上abstract 关键字构成,如: TParent = class procedure OneProc; virtual; abstract; function OneFun: Boolean; dynamic; abstract; end; 抽象方法和普通虚方法的区别: a. 抽象方法只有声明,没有实现;而虚方法必须有实现部分,哪怕没有实际代码而只有begin…end 头。 b.  抽象方法必须在子类中覆盖并实现后才用调用。因为没有实现的方法不能被分配实际地址,而 调用一个没有实际地址的方法显然是荒谬的。 所以,抽象方法也可以被称为纯虚方法。

如果一个类中含有抽象方法,那么这个类就成了抽象类,如TStrings 含有: procedure Clear; virtual; abstract; procedure Delete(Index: Integer); virtual; abstract; 等多个抽象方法。 抽象类是不应该直接用来创建实例的,因为一旦调用了抽象方法,将抛出地址异常,而我们很难 保证不在某些地方调用抽象方法。所以,尽管实例化抽象类是被允许的,却是应该避免的。 因此,抽象类一般都是中间类,实际使用的总是覆盖实现了抽象方法的子类。比如常用的字符串 列表类TStrings,我们总是使用它的子类而不是它本身来构造实例,如:

var Strs: TStrings; begin Strs := TStringList.Create; ⋯⋯ end;

========================================================

重载方法的几个特点: a. 可以分别是函数或者过程。因为在Delphi 中,可以将过程看做一个没有返回值的函数,一个函 数也可以当作过程调用。 b. 如果位于相同类中,都必须加上overload 关键字;如果分别在父类和子类中,那么父类的方法 可不加overload 而子类必须加overload。 c. 如果父类的方法是虚(virtual 或者dynamic)的,那么在子类中重载该方法时应该加上reintroduce 修饰字,否则会出现编译警告:“hides virtual method of base type”。当然只是编译时产生警告,如果你 不顾它的警告,坚持不加修饰字,对程序运行结果也不会造成影响。如: TParent = class procedure OneProc; virtual; end; TChild = class(TParent) procedure OneProc; reintroduce; overload; end; d. 在published 区不能出现多个相同的重载方法。如: TParent = class procedure OneProc; virtual; end; TChild = class(TParent) published procedure OneProc; reintroduce; overload; {和父类构成方法重载关系是可以的,因为在TChild的published区,只有一个OneProc方法,而下面两行企图重载AnotherProc则是没可能的,编译器不允许在published区出现 多个同名的方法} procedure AnotherProc(S: String); overload; procedure AnotherProc; overload; end;

===================================

消息方法。消息方法的作用是截获并处理特定的一个消息。它使用的声明关键字是message。如: TCustomForm = class(TScrollingWinControl) private procedure WMClose(var Message: TWMClose); message WM_CLOSE; ⋯⋯ end; TCustomForm 声明了一个消息方法WMClose,WMClose 的作用是捕获并处理消息WM_CLOSE。 当WM_CLOSE 消息到来时,方法WMClose 被自动调用。关于消息方法是如何被自动调用的,可以 参考“VCL 消息机制”的内容。 消息方法的规则命名:消息类名大写+‘_’+消息名(第一个字母大写,其余小写);当然这个规 则不是强制的,你可以任意命名它。 消息方法参数声明格式:var Message: 消息类型。消息类型可以是基本消息类型TMessage,也可 以是特定的消息类型(一般是规则消息方法名头部加‘T’),如上面的可以是TWMClose。特定消息类 型都是Delphi 预定义的,一般位于Messages 单元;一些和具体控件相关的消息类型则在该控件的定 义单元定义。 消息方法的实现类似下面的代码:   procedure TCustomForm.WMClose(var Message: TWMClose); begin {在本类中对消息作必要的处理} Close; {然后调用父类对该消息的处理代码} inherited; end;

==============================

绝大部分属性是可读也可写的,少部分是只读的。可读可写属性一般声明在published 区,供组件 用户在设计时存取属性值,只读属性一般声明在public 区,供运行时使用代码取值(典型的如

================================

(1)对于没有取值范围限制的属性,常常直接用字段来实现存取,如Controls 单元的片断: TControl = class(TComponent) ⋯⋯ private ⋯⋯ FHint: string; ⋯⋯ published ⋯⋯ property Hint: string read FHint write FHint; ⋯⋯ end. (2)当须要检查属性值的取值范围,或者须要执行一些附加操作时,通常采用方法来实现存取, 如TControl.Left 属性是这样声明的: property Left: Integer read FLeft write SetLeft; 方法SetLeft 实现如下: procedure TControl.SetLeft(Value: Integer); begin if Value <> FLeft then {如果新设定的值和原来的值相等,就没有必要执行下面的代码了} begin SetBounds(Value, FTop, FWidth, FHeight); {SetBounds内部执行FLeft := Value; SetBounds主要功能是根据新的Left、Top、 Width、Height属性值改变控件在界面上的显示位置} Include(FScalingFlags, sfLeft); end; end; TWinControl.Handle)。而只写属性在实际开发中几乎没有应用。

==========================

indexes 如果一个属性含有这个部分,那么该属性就具有数组的特点。indexes 就是存取数组元素时必须用 到的参数(我们将它理解为广义的数组元素索引)。一个很典型的例子是TCanvas 类定义的属性Pixels: TCanvas = class(TPersistent) private function GetPixel(X, Y: Integer): TColor; procedure SetPixel(X, Y: Integer; Value: TColor); public property Pixels[X, Y: Integer]: TColor read GetPixel write SetPixel; end; 当引用属性Pixels时,X和Y的值被自动传给GetPixel和SetPixel方法,这样GetPixel和SetPixel就可 以存取数组中有X和Y指定位置的元素了。

========================

接口和类的不同 (1)接口中只有方法、属性,没有字段。所以接口中的属性存取都必须通过方法。 (2)接口中的方法只有声明,没有实现。实现在类中完成。 (3)接口中的方法没有作用域。都是公开的,但是在类中则放到不同作用域。 (4)接口中的方法没有修饰字。可以认为它们都是抽象的。 (5)不能创建接口实例,要使用接口,必须在类中实现,通过类调用接口的方法。 (6)在类中必须声明和实现接口的所有方法。不像类继承中可以选择。 (7)接口中的方法在类中实现时,可以加virtual/dynamic、abstract 修饰,从而在子类中可以实现 覆盖。

再次深入理解delphi的类的更多相关文章

  1. 理解 Delphi 的类(十一) - 深入类中的方法[8] - 抽象方法与抽象类

    //抽象方法类似与接口; 在没有接口的年代 Delphi 是用抽象方法来模拟接口的; 我想它最终会被接口替代. {下面就定义了两个抽象方法} TMyClass = class(TObject)   p ...

  2. 理解 Delphi 的类(八) - 关于类的定义

      //标准语法   TMyClass1 = class(TObject)   end;   //如果是继承自 TObject 可以省略   TMyClass2 = class   end;   // ...

  3. 理解 Delphi 的类(十) - 深入方法[17] - 提前声明

    //要点17: 如果前面的方法要调用后面的方法, 后面的方法需要提前声明 function MyFunB(x: Integer): Integer; forward; {使用 forward 指示字提 ...

  4. 理解 Delphi 的类(十) - 深入方法[18] - 在接口区声明的方法都相当于提前声明了

    //要点18: 如果函数在接口区定义了, 就无需用 forward 提前声明了 unit Unit1; interface uses   Windows, Messages, SysUtils, Va ...

  5. 比较C++、Java、Delphi声明类对象时候的相关语法

    同学们在学习的时候经常会遇到一些问题,C++.Java.Delphi他们到底有什么不一样的呢?今天我们来比较C++.Java.Delphi声明类对象时候的相关语法.希望对大家有帮助! C++中创建对象 ...

  6. QMetaObject感觉跟Delphi的类之类有一拼,好好学一下

    提供了一堆原来C++没有的功能,比如反射什么的...但是可能还是没有Delphi的类之类更强,因为类之类可以“创建类”.可惜我学艺不精,对“类之类”也没有完全学会.先留个爪,有空把两个东西都好好学学, ...

  7. delphi 实体类 JSON 数组

    delphi 实体类 与JSON转换,序列化 TJson REST.JSON.pas   TJson.JsonToObjectTJson.ObjectToJsonString JsonEncode O ...

  8. Delphi 遍历类中的属性

    http://blog.csdn.net/easyboot/article/details/8004954 Delphi 遍历类中的属性 标签: delphistringbuttonclassform ...

  9. DELPHI学习---类和对象(五篇)

    Classes and objects(类和对象) 类(或者类类型)定义了一个结构,它包括字段(也称为域).方法和属性:类的实例叫做对象:类的字段.方法和属性被称为它的部件(components)或成 ...

随机推荐

  1. Java程序员必知的8大排序算法

    8种排序之间的关系 直接插入排序 (1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排 好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数 也是排好顺序的.如 ...

  2. Hadoop Hive概念学习系列之什么是Hive?(一)

    参考  <Hadoop大数据分析与挖掘实战>的在线电子书阅读                   http://yuedu.baidu.com/ebook/d128cf8e33687e21 ...

  3. hpuoj 问题 A: 做不出来踢协会!!!

    问题 A: 做不出来踢协会!!! 时间限制: 1 Sec  内存限制: 128 MB提交: 291  解决: 33[提交][状态][讨论版] 题目描述 这是今天最水的一道题,如果没写出来的,呵呵,踢协 ...

  4. ArrStack——数组栈(procedure)

    //数组栈,对于无法预料栈的长度情况下,可能会因为原分配数组不够长而导致数据溢出,或因为数组太长而浪费空间.但是操作快,不需要额外的操作.而链表与此想法,可以动态分配内存,但是要增加额外的操作. #i ...

  5. 通过代码来执行testng.xml

    大多数时候,我们都是通过Eclipse IDE上的操作命令来执行testng 框架下的case 运行.那如果我们不想通过这种方式,而是想通过代码调用来实现执行该怎么办?下面是我搜集的两种方式供大家参考 ...

  6. thinkphp 获取客户端ip地址方法

    /** * 获取客户端IP地址 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 * @param boolean $adv 是否进行高级模式获取(有 ...

  7. VM网络无法连接--提示ethernet0无法连接到虚拟网络

    打开 “编辑->虚拟网络设置"里面,点“恢复默认” 如果还不行 然后 开网络和共享中心 左击  本地连接(若是无线网络,则点击无线网络连接)----属性----共享---- 在:允许其 ...

  8. Windows如何打包Qt程序

    很多Qt爱好者想发布自己的Qt软件,但却发现在其他没有安装Qt SDK的机器上无法运行,这就是本文想要说明的问题.现在网上大部分软件都要发布自己开发的应用程序,都会打包到exe文件中,待安装完exe文 ...

  9. WCF - 序列化

    数据是信息的载体 在不同环境中有不同的类型 为保证处于不同平台的的应用能够正常的进行数据交互 必须采用一种双方都能理解的数据类型 XML无疑是最好的选择 但不是唯一的选择 例如JSON也是一种普遍认可 ...

  10. 覆盖equals的时候总要覆盖hashCode

    import java.util.HashMap; public class Student { private String name ; private String id; public Stu ...