第七章 Object Pascal面向对象设计
一、Delphi的类分两种:①继承delphi内建类的class类②完全自定义的object类
1、继承自delphi内建类的class类
语法:
type
类名 = class(父类)
类成员
end;
特点:①此种方法定义的类都是TObject类的子类。②类名是指针。导致无法定义一个类对象,定义的是类对象的指针,定义时并不调用类的构造函数。使用指针前必须先给指针赋值,同样的,使用定义的类对象指针前,必须先调用该类的create构造函数。有疑惑的可以试试sizeof(类名或类定义的变量名),xp+delphi7环境永远返回4。
构造和析构:create构造。对于析构,不要直接调用destroy,它只是删除对象的指针而并没有删除对象实体,在程序完全终止前,对象实体的内存空间将一直被占用。用free来代替destroy,不仅可删除对象指针,也可删除对象实体。
2、完全自定义的Object类
语法:
type
类名 = object(父类)
类成员
end;
特点:这种类型的类定义对象时,同C++中的类对象,不再是指针。sizeof返回类的大小,而非类指针的大小。
构造和析构:不需构造函数。对于析构,和record一样,当该对象离开其作用域时,自动释放占用的空间。
二、类成员的封装等级
private:仅可在该类声明所在的单元内使用。虽然父类的private成员可被子类继承,但子类不可访问它们。
protected:子类可访问。所以可在该类声明所在的单元和子类声明所在的单元使用,其他地方不可用。
public:类和子类的对象都可用。
published:其可见度同public一样,区别是delphi的对象监视器可直接显示本区域的成员,而此差别来自RTTI这个机制。
antomated:使用自动化服务器时,此保留字有用。
对开头不加保留字的类成员,其可见性参照前一个成员;若类中第一个成员不加保留字时,若该类本身或其父类是在使用“{$M+}”编译指令的情况下,则第一个成员默认为published成员,否则为public成员。
更改成员变量的封装等级:重新声明该成员就可更改父类成员变量在子类中的封装等级。但最好扩大其可见度而不要缩小其可见度。
三、类成员的定义与实现
类成员包括字段、方法和属性。属性与字段的区别,属性有些可读取或修改其内部数据的方法有关联。声明时,若某个字段是属性,则必须在属性名称前加保留字“property”,且需写出关联方法。如:property Max : Integer read FMax wirte SetMax default 100;可无默认值。
子类成员的存在方式:子类仅复制父类的字段、属性和方法的声明部分,对于父类的方法定义与实现部分,则保持父类原有的一份,因此,当子类的对象实体要使用由父类继承来的方法时,是根据所调用的成员函数名,去唤起父类的成员函数的实现部分。
成员函数介绍:
override、hide、overload:本质问题还是定义规则和使用规则(使用规则又分为适用条件和使用方法)。
1、override的定义规则:祖先类的virtual或dynamic方法才可被子类重写。祖先类的virtual和子类的override仅在声明时加,实现里不加。被重写的方法的声明(方法名、参数、返回值)必须完全与祖先类一样。
override的使用规则:导致动态绑定。
纯虚函数的定义规则:成员函数声明后加“virtual;abstract;”或“dynamic;abstract;”,且没有函数的实现部分。子类中必须override所有纯虚函数。
2、hide的定义规则:子类中有与父类函数名相同的函数,且该函数没有加overload。
hide的使用规则:导致不能使用动态绑定。即父类指针指向子类对象时,不能调用子类中与父类同名的方法。
3、overload的定义规则:同一个类中函数名相同参数不同的函数可构成重载。函数声明后加overload保留字,实现区不加overload。
4、静态绑定和动态绑定:静态绑定指在编译期间,就确定了函数调用的相应代码。动态绑定指在程序运行期间,据对象的实际类型调用相应的方法。
类中不加任何修饰符的成员函数,称之为静态方法。如:procedure Draw;编译期间,已绑定到它的实现方法。
对virtual成员函数,且子类override了此函数,即表示这个成员函数在编译时,会使用动态绑定的方式。
四、self、as、is、Sender、parent、owner、inherited介绍
1、self同this。可视为该对象的别名。
2、as:可将当前类或子孙类的对象强制转换为它本身或它的祖先类,然后调用祖先类的类成员。语法:object as class若object是class类的祖先类或无继承关系的类,则会引发编译时异常或运行时异常。运行时异常如图:说下这个图的由来:form上放置一个button和一个edit。在button的click事件中输入:ShowMessage((Sender as TButton).Caption);执行成功。然后将edit控件的click事件设置为button的click事件,则点击edit控件时就会触发此异常。
3、is:用来判断左方操作数这个对象实体,是否属于右方操作数那种类。语法:object is class;返回值为boolean型。Object对象是右方的class类或它的子类时,返回true;是其祖先类时,返回false。若无继承关系,编译错误。
as和is都遵循一个规则:男人是人,人不一定是男人。子类对象is/as父类。
4、sender:delphi中多个控件可共享同一个方法。比如button1、button2、button3的click事件都共用button1的click。其click方法的sender参数用来指明当前点击的是哪个button。简而言之,sender就是用来指出响应此事件的控件的句柄。
5、parent:读写属性。一个组件的parent,是指拥有该组件的父类。组件的parent必定是一个窗口控制组件,通常组件有parent这个属性,此属性用来设定父窗口。
组件的父类析构后,无法在画面上看到该组件的外观,并不表示它已经析构了。若当时组件的parent和owner是同一个组件,它才会被析构。
6、owner:只读。当owner析构时,它包含的组件也一块被析构。一个form上的所有控件其owner都是该form。
停靠:要让某个窗口具有可停靠属性,设置其DockSite = True;设置某控件具有停靠属性:设置其DragKind = dkDock; DragMode = dmAutomatic;然后就可以拖动该控件到设定了具有可停靠属性的窗口。
7、inherited:用在方法的实现区里,当设定子类的某个方法的实现内容时,若它只比父类的方法多些代码,这种情况,只需写inherited+父类的成员函数的标识符。相当于把父类的代码引入到子类中,可以少写不少代码。对引入父类的构造函数:首先,必须引入到子类的构造函数中;其次,只用写inherited;就行了。
五、静态成员函数
Delphi的成员函数在其他程序中相当于静态方法。像在C++、java都是在成员函数前加static。在C++、java中的static可用于成员变量和成员函数,是将该成员定义为类成员,而不是实体的成员。即static是用来定义类变量或类方法;反之,若不加static,则是定义实体变量或实体方法。Delphi不支持静态数据成员。
定义类方法时,需在方法名前加“class”,注意声明和实现部分都要加。对类方法,虽有self关键字,却无法访问成员变量、属性及一般方法,可访问类方法和构造函数。所有代码共享一开始就设置好的“类方法”。而对象方法,存在于此类的对象实体,每个对象实体都有自己的对象方法,且指向共享程序区段的对象方法,且可用self指出由哪个对象调用。
仿真静态数据成员:虽delphi不支持静态成员,但可用模拟方法做到这点。利用编译指令来实现。{$J+}之后以const关键字定义的常量是可被修改的,在{$J-}之后以const关键字定义的常量是不可被修改的。
下面是将number类方法当做静态数据成员来用。
TStaticMethod = class
class function Number(const nval : integer=0; const ischange : boolean=false):integer;
end;
class function TStaticMethod.Number(const nval : integer; const ischange : boolean):integer;
const
{$J+}data : integer = 0; {$J-}
begin
if (ischange) then
data := nval;
result := data;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
TStaticMethod.Number(100, true);
ShowMessage(inttostr(TStaticMethod.Number));//若不用{J+}和{J-},则弹出0。
end;
第八章 异常处理
比如说一个学校,有自己的运转规则,有自己的校规,对于触犯了规则的学生或老师,就会受到相应的规则处理。校规有很多条,触犯其中任何一条都会受到惩罚。随着社会发展,校规自然也会加入些新的规则。
异常处理就是预见程序可能发生异常的情况,并加以处理,避免程序因未处理异常而终止。异常就相当于触犯了规则的学生或老师,而异常处理就是教务处据校规作出的处罚。
一、异常的分类
如同校规有既有校规和新加校规一样,异常也分为delphi内建的异常类和自定义的异常类。在此,罗列下既有校规。
1、delphi内建的异常类:都继承自Exception类,都定义与“SysUtils”这个文件中,内建的异常类都以“E”开头。
Delphi提供的内建的异常类:
2、自定义异常类
异常类和一般类的自定义有个区别:它必须继承内建类Exception或某个子类。
二、触发异常的方法
触发异常不就是触犯校规吗。触发异常的方式,有两种:程序自动触发和自行触发。无论哪种方式触发异常,都需异常处理。
自行触发是利用raise指令触发。语法:raise异常对象实体;注意raise指令必须用于try…except或try…finally区。
三、异常处理情况
教务处对犯错的学生或老师就行处理就是异常处理。学校的处罚按照严重性可分为两种,开除和不开除。异常处理也分为两种:try…except…end和try…finally…end。
1、try…finally…end:先执行try…finally块,当有异常发生时跳出此块执行finally…end块,之后自动捕获被触发的异常,并将信息显示出来。无异常发生,顺序执行直到结束。
2、try…except…end:try…except块没有异常发生时,不执行except…end块;有异常发生时,直接跳到except…end块开始执行。except…end块用来对异常进行处理。