再次深入理解delphi的类
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的类的更多相关文章
- 理解 Delphi 的类(十一) - 深入类中的方法[8] - 抽象方法与抽象类
//抽象方法类似与接口; 在没有接口的年代 Delphi 是用抽象方法来模拟接口的; 我想它最终会被接口替代. {下面就定义了两个抽象方法} TMyClass = class(TObject) p ...
- 理解 Delphi 的类(八) - 关于类的定义
//标准语法 TMyClass1 = class(TObject) end; //如果是继承自 TObject 可以省略 TMyClass2 = class end; // ...
- 理解 Delphi 的类(十) - 深入方法[17] - 提前声明
//要点17: 如果前面的方法要调用后面的方法, 后面的方法需要提前声明 function MyFunB(x: Integer): Integer; forward; {使用 forward 指示字提 ...
- 理解 Delphi 的类(十) - 深入方法[18] - 在接口区声明的方法都相当于提前声明了
//要点18: 如果函数在接口区定义了, 就无需用 forward 提前声明了 unit Unit1; interface uses Windows, Messages, SysUtils, Va ...
- 比较C++、Java、Delphi声明类对象时候的相关语法
同学们在学习的时候经常会遇到一些问题,C++.Java.Delphi他们到底有什么不一样的呢?今天我们来比较C++.Java.Delphi声明类对象时候的相关语法.希望对大家有帮助! C++中创建对象 ...
- QMetaObject感觉跟Delphi的类之类有一拼,好好学一下
提供了一堆原来C++没有的功能,比如反射什么的...但是可能还是没有Delphi的类之类更强,因为类之类可以“创建类”.可惜我学艺不精,对“类之类”也没有完全学会.先留个爪,有空把两个东西都好好学学, ...
- delphi 实体类 JSON 数组
delphi 实体类 与JSON转换,序列化 TJson REST.JSON.pas TJson.JsonToObjectTJson.ObjectToJsonString JsonEncode O ...
- Delphi 遍历类中的属性
http://blog.csdn.net/easyboot/article/details/8004954 Delphi 遍历类中的属性 标签: delphistringbuttonclassform ...
- DELPHI学习---类和对象(五篇)
Classes and objects(类和对象) 类(或者类类型)定义了一个结构,它包括字段(也称为域).方法和属性:类的实例叫做对象:类的字段.方法和属性被称为它的部件(components)或成 ...
随机推荐
- PyH : python生成html
参考:Python PyH模块中文文档 1. 使用自己的css或者js文件. 写好自己的css以及js文件,比如mystyle.css.myjs.js. from pyh import * page ...
- poj 1258 Agri-Net【最小生成树(prime算法)】
Agri-Net Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 44827 Accepted: 18351 Descri ...
- AutoLayout--masonry使用
[label1 mas_makeConstraints:^(MASConstraintMaker *make) { //使左边间距为 make.left.equ ...
- XMPPFrameWork IOS 开发(六)聊天室
原始地址:XMPPFrameWork IOS 开发(六)聊天室 聊天室 //初始化聊天室 XMPPJID *roomJID = [XMPPJID jidWithString:ROOM_JID]; xm ...
- 黑马程序员_<<GUI(图形用户管理)-----2>>
--------------------ASP.Net+Android+IOS开发..Net培训.期待与您交流! -------------------- 8.对话框 对列出目录内容增加了对话框提示, ...
- Nginx+Tomcat的服务器端环境配置详解
这篇文章主要介绍了Nginx+Tomcat的服务器端环境配置详解,包括Nginx与Tomcat的监控开启方法,需要的朋友可以参考下 Nginx+tomcat是目前主流的Javaweb架构,如何让ngi ...
- 【转载】nginx 并发数问题思考:worker_connections,worker_processes与 max clients
注:这个文章主要是作者一直在研究nginx作为http server和反向代理服务器时候所谓最大的max_clients和 worker_connections的计算公式, 其实最后的结论也没有卡上公 ...
- String的成员方法的使用
<%@ page language="java" contentType="text/html; charset=gbk"%> <html&g ...
- strace使用详解(转) 分类: shell ubuntu 2014-11-27 17:48 134人阅读 评论(0) 收藏
(一) strace 命令 用途:打印 STREAMS 跟踪消息. 语法:strace [ mid sid level ] ... 描述:没有参数的 strace 命令将所有的驱动程序和模块中的 ...
- python 3Des 加密
import hashlib; from Crypto.Cipher import DES3 import base64 def create_key(sk): r=hashlib.md5(sk).d ...