国庆到,这里我首先感谢这将近一年来CSDN上的朋友给我帮助和关心。在这里我给识了不少高朋好友,这实在是难得。以下就把我在学习Delphi这个面向对象语言时,有关面对类与对象的一点拙见,写出来供大家参考吧,不妥之处,还大家指出。 浅谈Delphi中的类和对象
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;
//这个AForm和它所指向的Form实例共用同一段地址单元,所有对AForm操作都将反应
//到它所对应的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;
//放弃吧,不要再用抽象类,完全用它的“儿子”来你的事吧
StrLst.Add('I love China!');
StrLst.Free;
end;5.类是一种对数据和操作高度的封装机制
(一)数据封装
unit Unit2;interface
type
TEmployee=class
private
FName:String;
public
Constructor Create;
function GetName: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);
//用GetName来访问FName
AEmployee.Free;
end;
对数据的封装在编写组件时,用得非常多。
(二)操作封装
unit Unit2;interface
type
TDivision=Class
public
//多态性让你的程序更据有“柔韧性”
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。这是类为我们提供的“鱼和熊掌兼
得”之法。
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;
//这个AForm和它所指向的Form实例共用同一段地址单元,所有对AForm操作都将反应
//到它所对应的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;
//放弃吧,不要再用抽象类,完全用它的“儿子”来你的事吧
StrLst.Add('I love China!');
StrLst.Free;
end;5.类是一种对数据和操作高度的封装机制
(一)数据封装
unit Unit2;interface
type
TEmployee=class
private
FName:String;
public
Constructor Create;
function GetName: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);
//用GetName来访问FName
AEmployee.Free;
end;
对数据的封装在编写组件时,用得非常多。
(二)操作封装
unit Unit2;interface
type
TDivision=Class
public
//多态性让你的程序更据有“柔韧性”
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。这是类为我们提供的“鱼和熊掌兼
得”之法。
解决方案 »
- 有多少人是自己给自己打工的?就是自己接业务干
- 关于控制语句的后缀表达式
- 在线等待 30分--大虾帮忙看看怎么办(1.怎么把*.bmp转化为*.ico。 2.怎么让动态生成的RzShellTree1有click事件)
- 高分求救高手(不够再加):Delphi中如何实现4位小数?在线等候...
- 散分了,很简单的一个adoquery问题。
- 高分请教关于注册表的问题?
- 烦!散分!
- 哪有Active Skin下载,解密的??
- 散分了,哈哈现在人很现实........
- 请问那位知道讲解用delphi进行完全的api编程的书籍
- FastReport报表?
- 在delphi中怎么通过ip与远程Sql-Server相连接? 大大散分!来哦
就不要“戏弄”我了,哈哈!
你开心,所以我开心;
嘻嘻嘻我没以戏弄你啊嘻嘻嘻
gamaster(a明)
写的号//不是吹出来的:)
你很棒欧//所以向你学习;
今天说好不灌水的;
try
Result:=Num1/Num2;
except
Result:=0;//提供弹形处理机制,处理除数为0情况,提到最前边行不行?
end;
灌水啦
SendMessage(Combobox1.Handle, CB_SHOWDROPDOWN, 1, 0);
================================================================在我英雄年少时,有一个女生,她愿意为我失去生命……
她意志坚定地说:你再缠著我,我就去死。 在我负笈外地时,有一个女生,她愿意等我到下辈子……
她温柔婉约地说:你想成为我男朋友,等下辈子吧。 在我穷困潦倒时,有一个女生,她愿意与我共赴黄泉……
她眼眶泛红地说:你再不还我钱,我就与你同归于尽。
谢谢关注!
try
Result:=Num1/Num2;
except
Result:=0;//提供弹形处理机制,处理除数为0情况,提到最前边行不行?
end;
当然可以,我只是想在这里说一下面对对象程序设计中异常的好处。说句实话,我认为你的水平远在我之上,以后还请你多关照。:)
谢谢关注!
try
Result:=Num1/Num2;
except
Result:=0;//提供弹形处理机制,处理除数为0情况,提到最前边行不行?
end;
放到前面当然可以。我只是想在这里对大家说一下在面对对象程序设计中,异常处理的好处。 象我以前曾写过判断一个串是不是一个合法的日期格式时,我就是这样
写的:
function StrIsDate(DateStr:String):Boolean;
begin
Rusult:=True;
try
StrToDate(DateStr);
except
Result:=False;
end;
end;
我觉用异常处理写可以大大减少程序的复杂性。这可能会遗笑大家了,没关系,我不怕别人笑话我的无知,我只是给大家另一种考虑问题的方法(这种方法可能是笨了点,但是的确很用效。)话说回来,以上小小说的完全对的,而且要比我的方法好!谢谢!
有你这样的好老师,一定会有好徒弟!收我为徒吧!我是刚从VFP转学DELPHI的!QQ:29100489
CSDN同乐!
begin
(Sender as TCanvas).Brush.Color:=clRed;
end;
还是有错:voild class typecast,怎么回事?
================================================================CSDN 论坛助手 Ver 1.0 B0402提供下载。 改进了很多,功能完备!★ 浏览帖子速度极快![建议系统使用ie5.5以上]。 ★ 多种帖子实现界面。
★ 保存帖子到本地[html格式]★ 监视您关注帖子的回复更新。
★ 可以直接发贴、回复帖子★ 采用XML接口,可以一次性显示4页帖子,同时支持自定义每次显示帖子数量。可以浏览历史记录!
★ 支持在线检测程序升级情况,可及时获得程序更新的信息。★★ 签名 ●
可以在您的每个帖子的后面自动加上一个自己设计的签名哟。Http://www.ChinaOK.net/csdn/csdn.zip
Http://www.ChinaOK.net/csdn/csdn.rar
Http://www.ChinaOK.net/csdn/csdn.exe [自解压]
作老师不敢当,以后有什么问题我能帮得上的,我一定会尽力的。
其实程序员就应该多交流经验才能帮助互相更快的成长!
谢谢楼主了!
我一定好好钻研!
____()()
/ @@
`~~~~~\_;m__m._>o -------大米在哪里?大米在哪里??
不敢作你老师(怕误人子弟),多给你两分吧。哈哈:)