======================================================
注:本文源代码点此下载
======================================================
1.登不了大雅之堂地理解几个概念
说到类和对象,我们不能不提及这样几个概念:类,对象,实例。就我个人觉得可以这样来理解:对象指的是泛称,自然界的任何实体都可以看成一个对象;而类则是以这些对象某些特征而分成的一系列的种类;实例则是特指属于某一个类的一个对象。
好啦,这些大道理我就不用多说了。不如来一个“背道而驰”的作法,我们用delphi code 来阐述这些外国人提出的一些令我们中国人不好理解的概念吧:
var
abtn:tbutton;
定义abtn是属于tbutton类的一个对象,但abtn不能说是一个实例,因为它还没有创建,所以我们说这是定义了一个对象,如果说定义了一个实例,多多少少有
一些不够确切。:)
begin
abtn:=tbutton.create(self);//创建一个tbutton的实例
abtn.caption:='对象';
abtn.free;
end;
2.对象是一个地地道道的指针
从物理角度来看,对象就是一段地址空间,这段地址空间的标志就是我们定义的类“变量”。所以我们可以把对象看成一个类的指针。大家知道,要访问一个指针就
必须对指针初始化。对象的既然是一个指针,也必须对它进行初始化。如何初始化呢?
还是说指针的初始化吧。对于一个指针可以有以下两种方法来进行初始化:
(一)直接分配
var
pint:^integer;
begin
new(pint);
pint^:=12;
dispose(pint);
end;
(二)指向别的已分配空间的变量
var
pint:^integer;
i:integer;
begin
i:=12;
pint:=@i;
end;
有趣的是,对象这种“指针”也有两种方法初始化
(一)直接分配
var
aform:tform;
begin
aform:=tform.create(self);
aform.showmodal;
aform.free;
end;
(二)指向别的已分配空间的实例
var
aform:tform;
begin
aform:=self;
aform.caption:='知道了吗?为什么会这样呢';
end;
file://这个aform和它所指向的form实例共用同一段地址单元,所有对aform操作都将反应
file://到它所对应的form实例之上。
说到这,我们就很好解释为什么过程(函数)的对象参数传递时,象这样这的格式:
(一)procedure setedit(var edit:tedit);
begin
edit.text:='11';
end;
和
(二)procedure setedit(edit:tedit);
begin
edit.text:='11';
end;
效果是一样的了。(一)是把一个tedit实体作为参数引用的形式进行参数传递,(二)是把一个tedit的对象“指针”作为参数传递。
3.类可以理解成一种特殊的数据类型
我们知道数据类型可以进行强制类型转化,类即然可以理解成一种数据类型,那么它也应该可以进行类类型转。比方如下代码为一个按钮(button1)的单击事件:
(一)

代码
procedure tform1.button1click(sender: tobject);
var
acaption:string;
begin
acaption:=tbutton(sender).caption;//sender从tobject转化到tbutton
showmessage(format('you clicked ''%s'' !',[acaption]));
end;
在这段代码中,sender是一个tobject型对象,我们把它强制转化为tbutton类型。如你看得不清楚,可以参照一下我们通常的数据类型的转化:
(二)

代码
procedure tform1.button1click(sender: tobject);
var
s_str:string;
p_str:pchar;
begin
s_str:='i love china!';
p_str:=pchar(s_str);
s_str:='';
s_str:=string(p_str);
showmessage(s_str);
end;
但是在面对对象的程序设计过程中,强调的是安全性,如(一)的强制类型转化存在着不安全性。如下的代码,依然是写button1.onclick事件:
(三)
procedure tform1.button1click(sender: tobject);
begin
tcanvas(sender).brush.color:=clred;
end;
执行一下,就会出错。这样岂不是违背了面对对象的程序设计的宗旨了吗?没有,即然是类,就应该有类特定的类强制转化方法,改(三)的方法如下:
(四)
procedure tform1.button1click(sender: tobject);
begin
(sender as tcanvas).brush.color:=clred;
end;//用as来转化,as就可以把错误抓住,不会影响程序的正常运行。
说到这我顺便提一下vb吧,如果学过vb的人可能觉得其中的控件数组比较爽,尤其是在编写象计算器这样的程序时。但delphi给我们什么呢?答案是delphi也能快速简洁的开发出这样的程序。如是操作:在窗体上放一个edit和十个button,把button.caption分别设为'0','1','2',...'9',然后写一个按钮的onclick事件如下:
(五)
procedure tform1.button1click(sender: tobject);
begin
edit1.text:=edit1.text+(sender as tbutton).caption;
end;
把别的button的onclick事件都关联到button1click上,运行程序。拍拍手!这样计算器程序的雏形就具备了。我们用delphi的类类型转化,开发出来类似vb中的控件数组功能的程序也是很棒的嘛!:)
4.抽象类和它的实例
delphi中有一种类为抽象类,你不能天真的直接为它创建一个实例。如:tstrings类。如下代码:
(一)
var
strlst:tstrings;
begin
strlst:=tstrings.create;
strlst.add('i love japan!');
strlst.free;
end;
这是不对的。那如何为诸如tstrings这样的抽象类构造实例呢?答案是借助它的非抽象子类。我们知道tstrings有一个tstringlist非抽象子类。我们就可以这样作:
(二)
var
strlst:tstrings;
begin
strlst:=tstringlist.create;//借助其子类的构造器,对strlst进行子类化
strlst.add('i love china!');
strlst.free;
end;
(三)
var
strlst:tstringlist;
begin
strlst:=tstringlist.create;
file://放弃吧,不要再用抽象类,完全用它的“儿子”来你的事吧
strlst.add('i love china!');
strlst.free;
end;
5.类是一种对数据和操作高度的封装机制
(一)数据封装

代码
unit unit2;
interface
type
temployee=class
private
fname:string;
public
constructor create;
functiongetname:string;
procedure setname(aname:string);
end;
implementation
{ temployee }
constructor temployee.create;
begin
fname:='blazingfire';
end;
function temployee.getname: string;
begin
result:=fname;
end;
procedure temployee.setname(aname: string);
begin
fname:=aname;
end;
end.
如上代码,我们就用了一个过程setname和一个函数getname对私有变量fname进行完全的封装。我们要对fname操作就只有这样:

代码
uses
unit2;
procedure tform1.button1click(sender: tobject);
var
aemployee:temployee;
begin
aemployee:=temployee.create;
aemployee.setname('rose');//利用setname来设置fname
messagebox(handle,pchar(aemployee.getname),'empoyee',0);
file://用getname来访问fname
aemployee.free;
end;
(二)操作封装

代码
unit unit2;
interface
type
tdivision=class
public
file://多态性让你的程序更据有“柔韧性”
function getdiv(num1,num2:double):double;overload;
function getdiv(num1,num2:integer):integer;overload;
end;
implementation
{ division }
function tdivision.getdiv(num1, num2: double): double;
begin
try
result:=num1/num2;
except
result:=0;//提供弹形处理机制,处理除数为0情况
end;
end;
function tdivision.getdiv(num1, num2: integer): integer;
begin
try
result:=num1 div num2;
except
result:=0;//提供弹形处理机制,处理除数为0情况
end;
end;
end.
如上代码我们通过类的多态性机制把除法分别处理成整除和非整除,又通过异常处理屏去除数为0的情况,从而保证操作的安全性,在调用时,我们就可以这样来:

代码
uses
unit2;
{$r *.dfm}
procedure tform1.button1click(sender: tobject);
var
division:tdivision;
ivalue:integer;
fvalue:double;
begin
division:=tdivision.create;
ivalue:=division.getdiv(1,2);
fvalue:=division.getdiv(1.0,2);
ivalue:=division.getdiv(1,0);
fvalue:=division.getdiv(1.0,0);
division.free;
end;
6.类是一种代码重用机制
比方在5中我们想对这个类加上一个getadd函数来作加法运算就可以用类的继承。如下写就可以了:
(一)

代码
unit unit2;
interface
type
tdivision=class
public
function getdiv(num1,num2:double):double;overload;
function getdiv(num1,num2:integer):integer;overload;
end;
type
toperation=class(tdivision)
public
function getadd(num1,num2:double):double;
end;
implementation
{ division }
function tdivision.getdiv(num1, num2: double): double;
begin
try
result:=num1/num2;
except
result:=0;
end;
end;
function tdivision.getdiv(num1, num2: integer): integer;
begin
try
result:=num1 div num2;
except
result:=0;
end;
end;
{ toperation }
function toperation.getadd(num1, num2: double): double;
begin
result:=num1+num2;
end;
end.
这里我们从tdivision继承了一个子类toperation。toperation就可以即有tdivsion公有方法getdiv,又有自己的独特的方法getadd。这是类为我们提供的“鱼和熊掌兼得”之法。不错吧。:)
======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
深入理解Delphi对象与类
3496

被折叠的 条评论
为什么被折叠?



