type
my1=class
procedure a();
procedure hello();overload;
end;
type
my2=class(my1)
procedure a();
procedure hello();overload;
end;
//**********************************
这是完全可以正确运行的类,D6编译通过。
现有疑惑数点,希望大家指教。
1.为什么my2中的procedure a自动重载了my1中的procedure
2.为什么procedure hello声明为重载,却实现了多态?
3.如果把my1中的overload改为virtual,把my2中的overload改为override则出现运行时错误,为什么?
my1=class
procedure a();
procedure hello();overload;
end;
type
my2=class(my1)
procedure a();
procedure hello();overload;
end;
//**********************************
这是完全可以正确运行的类,D6编译通过。
现有疑惑数点,希望大家指教。
1.为什么my2中的procedure a自动重载了my1中的procedure
2.为什么procedure hello声明为重载,却实现了多态?
3.如果把my1中的overload改为virtual,把my2中的overload改为override则出现运行时错误,为什么?
解决方案 »
- 求高手解决delphi处理excel数据问题
- 如何截获 webbrowser 点击超链接事件?
- 问一个关于socket发送与接收数据的问题?
- Delphi is nothing comparing to Java!!!!!!
- 有关窗口调用的另一类问题
- 各位高人:怎样讲统计图表和统计表格打印在一起,图表是用TDBChart,表格用DBGrid,怎么办
- 哪有绝对可用的Delphi6中文版下载??
- 别见笑,一个菜问题.
- 5岁的小新,请过来!5岁的小新,请过来!5岁的小新,请过来!5岁的小新,请过来!5岁的小新,请过来!5岁的小新,请过来!
- 是否用Delphi连接远程数据库是必须安装数据库软件?
- 在TSQL中使用类似函数的问题?
- delphi中连接sql2000数据库的方法,是否有专用接口,ado还是bde
1.我不太明白,为什么不说我重复定义
2.我申明为overload的目的不是要实现多态,而是要检验一下overload和override的区别,我只知道overload可以实现重载,不知道他能实现多态,这里实现多态的似乎不是overload的作用,理由:1中就已经实现的多态
3.我看的书上写的就是基类用virtual,派生类用override,呵呵,所以不明白。ps:谢谢你的关注。
2. my2 procedure hello , 也没有实现重载, 你在那里加不加overload都是一样的效果
overload ,在一个类中是实现同名过程或函数的功能, 建议你多看看语法书
3。 不会出错,你肯定是在hello; virtual; 中间少了分号
---------------------------
Access violation at address 004036F6 in module 'Project1.exe'. Read of address 74DB8417.
代码:
type
my1=class
procedure a();
procedure hello();virtual;
end;
type
my2=class(my1)
procedure a();
procedure hello();override;
end;
调用:
m1.hello;//这里就出现上面的错误。
虚函数是不能被自己的调用的, 只能被它的继承类调用
m2.hello;//m2是my2的实例
也出现上面的错误。
var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
var m1:my1;
m2:my2;
begin
m1.Create;
m2.Create;
m2.hello;
end;
procedure my1.hello();
begin
showmessage('my1');
end;
procedure my2.hello();
begin
showmessage('my2');
end;
procedure my1.a();
begin
showmessage('a1');
end;
procedure my2.a();
begin
showmessage('a2');
inherited;
end;
end.
my1的a没有丝毫关系
2. 这个跟多态没有关系 ,你声明的重载由于他们是在两个不同的类中
所以能通过编译是很正常的,如果你把那两个方法写在同一个类中我想多半
是编译通不过的
3. 出现运行时错误可能时你的代码没有些对,你的第三个问题所描述的才是真正的
多态机制(用虚函数来实现晚期绑定)如果你还有什么问题,可以和我短消息联系,或者发邮件[email protected]
我对delphi中的面向对象也比较感
兴趣
************************************************
* 伟大、光荣、正确的中国共产党万岁! *
* 万岁!万岁!万万岁! *
************************************************
不知道Delphi中的多态和重载是否和C++中的解释一样。
在一个类中,多个函数重名,并且参数类型或者个数不同,就是重载
基类与派生类之间函数重名,并且参数类型与个数完全相同,就是多态
在Delphi中我也是这样理解的,不知道是否正确。
你没实例化^_^
m1 ;= my1.Create;
m2 := my2.Create;to: FrameSniper(凤凰是否真的能够涅磐?)
我说的是楼主的那样实现的就没有任何关系^_^
m1 ;= my1.Create;
m2 := my2.Create;to: FrameSniper(凤凰是否真的能够涅磐?)
我说的是楼主的那样实现的就没有任何关系^_^
对于DWGZ的话“1. my2 procedure a 并没有重载 my1 的 procedure a, 它已经是已my1没有任何关系的新函数了”我表示不赞同:这两个函数不是没有关系,而是关系体现的不很明显了,既然是直接继承的关系,怎么可能没有关系呢。
请给兄弟们说一说你的想法
////引用
{begin Delphi中一个很容易混淆的概念就是重载和覆盖:重载可以实现多态,而多态是面向对象三个特性中最最重要的一个;而对于覆盖(override)只是一种简单的语法现象,和面向对象没有任何的关系。end }这段话好像有错误呀。
overload == 多态?No.
重载与多态是两个世界的,可在在多态中有overload的体现,但没有说因为出现了overload就是多态,但出现了向上引用,就产生了多态。我之前写的关于多态的阐述,可以参考{
也谈多态
封装、继承、多态构成了OOP的三大基本核心,封装、继承在之前我们曾作过介绍,而多态没有进行详细的介绍,在此给以补充,以完成OOP的三大主题来结束OOP的那一块。关于多态在很多资料上都有介绍,而且介绍的非常精彩,那么就让这篇文章再来进行一次总绍吧。
首先说点废话,以下的介绍以及实例中,我将以Object Pascal作为讲解的工具,而多态实质上是OOP的,不属于某一个工具的,它是一种信仰。在此处虽然以Objec Pascal来进行描述,其实可以扩展到任何的语言中。言归正转,继续我们的话题。
什么是多态?多态的本质是什么?多态和封装、继承有什么关系?它在OO中站有什么样的地位?多态给我们的工作代来了什么?本文就对这些问题加以阐述,在阐述的过程中来理解多态,认识多态,应用多态。
什么是多态?似乎没有一个统一的定义来规范多态,或许以我们自己的理解方式来解释多态更为贴切,在此我们不引用一些术语来进行定义,就初学者也可以理解的方式来形像这个定义:多态,顾名思议,就是多种形态,而这种多种形态又具体又体现在了什么地方?可以这样理解,我们可以用一种轮廓的物体来描述不至一种的多个物体,而至于我们到底要描述那个物体的状态,对于我而言不很重要。为什么要这样说呢?多态就是给我们体供了这样一种机制,我们对它仅仅是一个形式上的声明、定义,而具体的实现上的细节我们没有必要在此进行关心。或是具体的实现细节将交给别的东西去实现。我们所声明的这个基类从某种意义上而言只是一种定义。就如接口一样,没有实现部分,说到这儿,不得不说多态的本质了。多态的本质就是基类提供一系列的虚拟方法,如果试图去实现这个基类的话,将被编译器告之这样是行不通的。多态性的完整提体是交对象和他的子对象共同完成的一个思维方式。 多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。对于用户而言,他们所关心的只不过是那些没有实现细节的父类所提供的虚拟方法罢了。如果以接口的话来讲就是:我们不去关心,也没有必要去关心接口的实现细节,我们所关心的仅仅是接口为我们提供的方法来完成我们的功能,而至于接口以何种方式来实现我们所需要的不同功能甚至是一个特定方式的多个功能都是其内部的事。不知道这样的解释是否让大家感觉很模糊,在理解上是否感觉不能很好的接受。请继续往下看。
谈到多态,我们首先要明白,对于多态而言,其父类提供了很多的虚拟方法,所以我们没有办法去直接实现这个父类,只能通过它的派生类去覆盖其提供的虚拟的方法,所以这就产生了多态。我们都知道,一个类可以被多个子类所继承,而每个子类所实现的方法又不一至,或是根据它们自己特有的特点对一个特定的方法的实现上因为类差别而存在着差别,但是我们完全可以通过父类去模糊化这些操作。对子类的方法的调用完全都可以通过基类去实现。由此而言,如果此基类没有被派生,那么这个类是完全没有存在的意义的!只有它被某一个子类派生了,那么它就正真的有存在的意义了。这种意义又提体在什么地方?或我们以什么手段来让这种意义成为焦点呢?这就是我们需要进一步走进多态的原因,如下所示:
TA = Class
Public
Procedure A ; virtual ; abstract;
Procedure B ; Virtual ; abstract;
Procedure C ; virtual ; abstract;
end;
当我们声明了类TA时,可以看到它有三个方法,而且也注意到了这三个方法都是完全虚拟的,如果此时我们试图实例化这个TA,将会没有任何的意义的,因为我们无法去实现类TA给我们提供的各种方法,或者说编译器将不提供空间/机制来让我们实现这些虚拟的方法。只有通过其子类进行覆盖这些虚拟方法才可以正真的将它们提体出它的作用。而覆盖就是说子类重新的定义、实现了基类的方法。如:
TB = Class(TA)
Private
B_Str : String;
Public
Constructor Create(Value : String);
Destructor Destroy();override;
{这是覆盖。设么地方可以用override?当他积累相对应的方法是虚拟的或是动态的时候才可以用override}
Procedure A ; override;
Procedure B ; override;
Procedure C ; override;
end;
TC = Class(TA)
Private
C_Str : String;
Public
Constructor Create(Value : String);
Destructor Destroy();override;
Procedure A ; override;
Procedure B ; override;
Procedure C ; override;
end;
这里有一个初学者或是不太注意语法的人经常混淆的概念。覆盖(override)和重载(overload)。上面说了,覆盖是指子类重新定义父类的虚函数的做法(inherted的用法是什么意思你真正的明白吗?)。而重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。如下:
Procedure OpenSQL(Sender : TADOQuery;SQLStr : String); overload;
{当重复时,返回为False,否则返回为True}
Function OpenSQL(SQLStr : String) : Boolean ; overload;
Function ifrepeat(TableName,FieldName,FieldValue : String;IntValue : Integer = 0):Boolean;overload;
Function ifRepeate(TableName : String;FieldName , FieldValue :
Array of String) : String ;overload;
可以很清晰的看到上边的代码就是一个子类覆盖了基类的虚拟方法的过程,而此时还不能很明确的提体出来多态的特性,或是说多态的本质问题还没有提体出来,并且您可能于晚期绑定也不是很明白,下边将给以解释。
当我们从抽象类TA派生出了类TB和TC,并且,子类也覆盖了基类的虚拟方法,现在如何应用这些方法呢?我们将以什么样的形式去调用这些方法呢?这才是多态最值得焦点的时刻,也是最能体现多态的本质的地方,之前已经给您灌输了多态的本质就是将子类类型的指针赋值给父类类型的指针,只要这样的赋值发生了,多态也就产生了,因为实行了“向上映射”。何以这样说呢?请继续我们的实例,假设它们的实现方法分别如下:
{ TC }
procedure TC.A;
begin
inherited;
{inherted的意思就是把相应的消息交给其父类去处理,他不属于我们讨论的范畴}
ShowMessage('TC' + C_Str);
end;
……
{ TB }
procedure TB.A;
begin
inherited;
ShowMessage('TB' + B_Str);
end;
……
现在我们就可以通过父类来来对子类进行调用,而这个过程其实就是一个“向上映射“的过程,既:子类类型的指针赋值给父类类型的指针;我们可以在此定义一个全局的过程来验证我们上边的话:
Procedure Test(Const pA : TA);
begin
pa.A;
{请将您的注意力放在此处,我们说了,TA是一个抽像类,它所提供的方法都是虚拟的,只有被覆盖了才可以进行应用,那么此处的处理是否是正确的呢?答案是肯定的,于是,多态在此处便提体的淋漓尽止,同时我也给出了调用的过程}
end;
procedure Tform.ButtonClick(Sender: TObject);
var
vTC : TC;
begin
vTC := TC.Create('多态实例_vTC');
Test(vTC);
vTC.Free;
end;
{此时你是否可以看明白了这种“向上映射“的机制呢?vTC做为一个子类TC的引用值(对象指针),完全可以赋值给其基类TA,于是,此处就发生了子类类型的指针赋值给父类类型的指针,于是多态就产生了!!!}
此处再一次的对晚期绑定或是动态进行说明:当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态(记住:是动态!)的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚邦定)。
我想,此时,你应该对多态很明白了吧,那么我们讲了多态是OOP的一个重中之重,那么它倒底有什么作用?它给我们的项目将会带来什么效率上的飞跃呢?仅仅是为了完成某种实现方法吗?仅仅是作为一个概念而存在吗?这些都是我们在理解了多态之后必须去思考的东西。那么下边就多态将会如何的影响我们的效率进行阐述。我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!
如果还没有很明白多态,不妨参考下边的例子。
在这个问题上可以这样说:大炮可以打鸟,火枪也可以打鸟,你用那个?我不管是大炮还是火枪,我只知道他们都可以打鸟!向恐龙一样大的鸟我用大炮(就是一个例子,哪有那么大的鸟啊?打什么鸟对于长官来说就是一句话:打死它们,用什么?他不管),小鸟我用火枪。敌人来了我还可以打敌人,这就是动态的最终解释和一种接口重用!
有很多地方我是应用前辈的话。
}
m1:=my1.Create;
m2:=my2.Create;
m2.hello;//showmessage('a2');
m1.hello;//showmessage('a1');
//***********************定义如下
type
my1=class
procedure a();
procedure hello();virtual;
end;
type
my2=class(my1)
procedure a();
procedure hello();override;
end;
implementation
procedure my1.hello();
begin
showmessage('my1');
end;
procedure my2.hello();
begin
showmessage('my2');
end;
楼上:
////引用
{begin Delphi中一个很容易混淆的概念就是重载和覆盖:重载可以实现多态,而多态是面向对象三个特性中最最重要的一个;而对于覆盖(override)只是一种简单的语法现象,和面向对象没有任何的关系。end }这段话好像有错误呀。
=============================================
我觉的这段话是正确的,呵呵.
Overload是什么?不算是OO的特性。
覆盖(override)和重载(overload)。
覆盖是指子类重新定义父类的虚函数的做法。
而重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
其实,重载的概念并不属于“面向对象编程”,重载的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的(记住:是静态)。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!真正和多态相关的是“覆盖”。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态(记住:是动态!)的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚邦定)。结论就是:重载只是一种语言特性,与多态无关,与面向对象也无关!
引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚邦定,它就不是多态。”
那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了--代码重用。而多态则是为了实现另一个目的--接口重用!
overload -> override
覆盖(override)和重载(overload)。
覆盖是指子类重新定义父类的虚函数的做法。
而重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
其实,重载的概念并不属于“面向对象编程”,重载的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的(记住:是静态)。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!真正和多态相关的是“覆盖”。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态(记住:是动态!)的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚邦定)。结论就是:重载只是一种语言特性,与多态无关,与面向对象也无关!
引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚邦定,它就不是多态。”
那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了--代码重用。而多态则是为了实现另一个目的--接口重用!
兄弟你理论讲了一大堆, 不好意思你跟我执行一下, 你能通过你就可以到Borland工作了
procedure hello(); virtual; abstract;
procedure TForm1.Button2Click(Sender: TObject);
begin
m1.hello;
end;
做一下试验就行了type
my1=class
procedure a();
procedure hello();virtual;
end;
type
my2=class(my1)
procedure a();
procedure hello();override;
end;{ my1 }procedure my1.a;
begin
showmessage('my1-a');
end;procedure my1.hello;
begin
showmessage('my1-hello');
end;{ my2 }procedure my2.a;
begin
showmessage('my2-a');
end;procedure my2.hello;
begin
showmessage('my2-hello');
end;
1.为什么my2中的procedure a自动重载了my1中的procedure
到底有没有重载,看看就知道了
var a1:my1;
a2:my2;
begin
a1:=my1.Create;
a2:=my2.Create;
my1(a2).a; //'my1-a'
a2.a; //'my2-a'
end;也许你还有疑问,那么来看你的第三个问题3.如果把my1中的overload改为virtual,把my2中的overload改为override则出现运行时错误,反正我这里不出错var a1:my1;
a2:my2;
begin
a1:=my1.Create;
a2:=my2.Create;
my1(a2).hello; //'my2-hello'
a2.hello; //'my2-hello'
end;这两个问题不用再回答了吧?看第二个2.为什么procedure hello声明为重载,却实现了多态?
我怎么觉得多态就是通过重载来体现的呀?
1,我认为My2中的a()把My1中的a()隐藏,编译的时候应该会有提示的,如果要解决这个问题就应该在My2的a()后面加上reintroduce2比较同意FrameSniper(凤凰是否真的能够涅磐?) 的观点3在父类里的过程和函数后面加上vitrual和dynamic就是声明它们为虚拟和动态方法,它们在子类里是可以覆盖的,也就是override,而后面不加什么实际上就是申明过程和函数为静态的
begin
////->这里不用inherited吗?
showmessage('my2-hello');
end;
************
看第二个2.为什么procedure hello声明为重载,却实现了多态?
我怎么觉得多态就是通过重载来体现的呀?
*************
这点不明白,多态怎么是通过重载来体现的呢?
showmessage('my1-hello');
然后
showmessage('my2-hello');
什么是多态? procedure foo(i: integer); overload; procedure foo(d: double); overload; procedure foo(v: variant); overload; var v: variant; begin foo(1); //integer版本 foo(v); //variant版本 foo(1.2); //variant版本(浮点数,作为extended类型解释) end;
If you overload a virtual method, use the reintroduce directive when you redeclare it in descendant classes. For example,type T1 = class(TObject)
procedure Test(I: Integer); overload; virtual;
end;
T2 = class(T1)
procedure Test(S: string); reintroduce; overload;
end;
...
SomeObject := T2.Create;
SomeObject.Test('Hello!'); // calls T2.Test
SomeObject.Test(7); // calls T1.TestWithin a class, you cannot publish multiple overloaded methods with the same name. Maintenance of runtime type information requires a unique name for each published member.type TSomeClass = class
published
function Func(P: Integer): Integer;
function Func(P: Boolean): Integer // error
...Methods that serve as property read or write specifiers cannot be overloaded.
这是一件很难的事, 非常多的Delphi书籍都对该问题一带而过. 我整理了一下手边的资料, 关于
"多态性"的解释大概有如下几种:
------------------------------------------------------------------------------------------
1. 《Delphi 5编程实例与技巧》
面向对象的程序设计语言还可以在运行时才确定对象方法的调用地址,这种调用函数的方式叫做
多态性,有时也称为动态联编或滞后联编。 2. 《Delphi 5开发人员指南》
《Delphi 5高级编程 - IDE与面向对象编程》
多态性,从字面上说,是指多种形状。调用一个对象变量的方法时,实际被调用的代码与实际
在变量中的对象的实例有关。 3. 《Delphi 5企业级解决方案及应用剖析》
多态性,是指不同类型的对象可以对相同的激励做出适当的不同相应的能力。 4. 《delphi2高级程序设计指南》
《DELPHI基础教程 - 第二章: Delphi面向对象的编程方法(四)》
[参见: http://www.fosu.edu.cn/netschool/delphi/009.htm]
多态性是在对象体系中把设想和实现分开的手段。
如果说继承性是系统的布局手段,多态性就是其功能实现的方法。多态性意味着某种概括的动作
可以由特定的方式来实现,这取决于执行该动作的对象。多态性允许以类似的方式处理类体系中类似
的对象。根据特定的任务,一个应用程序被分解成许多对象,多态性把高级设计处理的设想如新对象
的创建、对象在屏幕上的重显、程序运行的其它抽象描述等,留给知道该如何完美的处理它们的对象
去实现。 5. 《Delphi4 编程技术内幕》
多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就
可以根据当前赋值给它的子对象的特性以不同的方式运作。
(简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针) 6. 《对象式程序设计方法》
[参见: http://www.cx66.com/cxgzs/project/00276.htm]
多态性,与一名多用、动态定连紧密联系在一起。多态的一般含义是,某一论域中的元素可以有
多种解释。多态性在形式上表现为一个方法根据传递给它的参数的不同,可以调用不同的方法体,实
现不同的操作。将多态性映射到现实世界中,则表现为同一个事物随着环境的不同,可以有不同的表
现形态及不同的和其他事物通信的方式。 7. 《C++》
[参见: http://www.kohua.com.cn/ruan/ye/yuyan/C++.htm]
多态性:给行为取一个名字或符号,它共享一个类的层次,在这个层次中的每个类都以适合自己
的方式实现这个行为。 ...
------------------------------------------------------------------------------------------ 哈哈, 不能再列举下去了. 如果再多一些, 大家的头不昏, 我的头也要昏了.
大家和和气气讨论问题就是了,恳请baguli(巴古里) 大哥为大家传道!************************************************
* 伟大、光荣、正确的中国共产党万岁! *
* 万岁!万岁!万万岁! *
************************************************
对多态性概念的演示程序.
Writed By Aimingoo.
}program ObjectSample;
{$APPTYPE CONSOLE}type
TMyObjectBase=Class(TObject)
function doit(i:integer): integer; virtual;
function doit_2(i:integer) : integer;
end; TMyObject=Class(TMyObjectBase)
function doit(i:integer): integer; override;
function doit_2(i:integer) : integer;
end; TMy=Class(TObject)
private
aMyObject : TMyObjectBase;
public
constructor Create(aObj:TMyObjectBase);
function DoCall(i:integer):integer;
function DoCall_2(i:integer):integer;
end;function TMyObjectBase.doit(i:integer):integer;
begin
result := -1;
end;function TMyObjectBase.doit_2(i:integer):integer;
begin
result := -2;
end;function TMyObject.doit(i:integer):integer;
begin
result := i * 5;
end;function TMyObject.doit_2(i:integer):integer;
begin
result := i;
end;constructor TMy.Create(aObj:TMyObjectBase);
begin
inherited Create;
aMyObject := aObj;
end;function TMy.DoCall(i:integer):integer;
begin
result := aMyObject.doit(i);
end;function TMy.DoCall_2(i:integer):integer;
begin
result := aMyObject.doit_2(i);
end;//示例代码开始
//---------------------
var
ObjBase : TMyObjectBase;
Obj : TMyObject;
CallObj : TMy;const
TestInt = 15;
begin
ObjBase := TMyObjectBase.Create;
Obj := TMyObject.Create; writeln('开始演示直接调用的情况...');
writeln('----------------------'); writeln('直接调用TMyObjectBase.doit(). 返回结果值应当恒为 -1');
writeln(' ==> ', ObjBase.doit(TestInt));
writeln('直接调用TMyObject.doit(). 返回结果值应当为', TestInt, ' * 5');
writeln(' ==> ', Obj.doit(TestInt));
writeln('直接调用TMyObjectBase.doit_2(). 返回结果值应当恒为 -2');
writeln(' ==> ', ObjBase.doit_2(TestInt));
writeln('直接调用TMyObject.doit_2(). 返回结果值应当为', TestInt);
writeln(' ==> ', Obj.doit_2(TestInt)); writeln;
writeln('TMy.aMyObject.doit()受到多态性影响...');
writeln('----------------------------------'); CallObj := TMy.Create(ObjBase);
writeln('此处使用TMyObjectBase.doit()来调用, 结果为-1');
writeln(' ==> ', CallObj.DoCall(TestInt));
CallObj.Free; CallObj := TMy.Create(Obj);
writeln('由于多态性的缘故, 此处使用TMyObject.doit()来调用, 结果为', TestInt, ' * 5');
writeln(' ==> ', CallObj.DoCall(TestInt));
CallObj.Free; writeln;
writeln('TMy.aMyObject.doit_2()没有受到多态性影响...');
writeln('----------------------------------------'); CallObj := TMy.Create(ObjBase);
writeln('使用TMyObjectBase.doit_2(), 结果为-2');
writeln(' ==> ', CallObj.DoCall_2(TestInt));
CallObj.Free; CallObj := TMy.Create(Obj);
writeln('使用TMyObjectBase.doit_2(), 结果为-2');
writeln(' ==> ', CallObj.DoCall_2(TestInt));
CallObj.Free; write('-- Press ENTER key to end...':79);
readln;
end.
我不敢苟同,
var a1:my1;
a2:my2;
begin
a1:=my1.Create;
a2:=my2.Create;
my1(a2).a; //你这只是强制转化,把a2 转为 my1, 那么它现在只是调用my1 的
// a 方法, 并没实现重载,
//对于类my2来说它已经是一个全新方法, 你自己可以用一个全局变量
//试验一下
a2.a;
end;
我不敢苟同,
var a1:my1;
a2:my2;
begin
a1:=my1.Create;
a2:=my2.Create;
my1(a2).a; //你这只是强制转化,把a2 转为 my1, 那么它现在只是调用my1 的
// a 方法, 并没实现重载,
//对于类my2来说它已经是一个全新方法, 你自己可以用一个全局变量
//试验一下
a2.a;
end;
to ihihonline(小小)
兄弟你理论讲了一大堆, 不好意思你跟我执行一下, 你能通过你就可以到Borland工作了
procedure hello(); virtual; abstract;
procedure TForm1.Button2Click(Sender: TObject);
begin
m1.hello;
end;不好意思,试问一下,procedure hello(); virtual; abstract;//你如何来实现呢?那么my1.hello又将从那儿来呢?我不知道您到底想说明什么问题,如果您觉的procedure hello(); virtual; abstract;也可以被完全的实现的话,是不是有点太那个了?
如果您想要的是Procedure Hello() ; virtual又何尝不可以呢?您可以试着运行下边的程度。unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type TA = Class
Public
Procedure A ; virtual ;
Procedure B ; Virtual ;
Procedure C ; virtual ;
end; TB = Class(TA)
Private
B_Str : String;
Public
Constructor Create(Value : String);
Destructor Destroy();override;
{这是覆盖。设么地方可以用override?当他积累相对应的方法是虚拟的或是动态的时候才可以用override}
Procedure A ; override;
Procedure B ; override;
Procedure C ; override;
end; TC = Class(TA)
Private
C_Str : String;
Public
Constructor Create(Value : String);
Destructor Destroy();override;
Procedure A ; override;
Procedure B ; override;
Procedure C ; override;
end; TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Procedure Test(Const pA : TA);
Procedure Tests(Const pB : TB);
end;var
Form1: TForm1;implementation{$R *.dfm}{TA}procedure TA.A;
begin
ShowMessage('TA-A');
end;procedure TA.B;
begin
ShowMessage('TA-B');
end;procedure TA.C;
begin
ShowMessage('TA-C');
end;{ TB }procedure TB.A;
begin
inherited;
//。。
ShowMessage('TC' + B_Str);
end;procedure TB.B;
begin
inherited;
//..
ShowMessage('TB' + B_Str);
end;procedure TB.C;
begin
inherited;
//..
end;constructor TB.Create(Value: String);
begin
//..
end;destructor TB.Destroy;
begin
//..
inherited;
end;{ TForm1 }procedure TForm1.Test(const pA: TA);
begin
pa.A;
end;procedure TForm1.Button1Click(Sender: TObject);
var
vTC : TC;
begin
vTC := TC.Create('多态实例_vTC');
Test(vTC);
vTC.Free;
end;procedure TForm1.Tests(const pB: TB);
begin
TB.Create('aaa');
pb.A;
end;{ TC }procedure TC.A;
begin
inherited;
//..
ShowMessage('a');
end;procedure TC.B;
begin
inherited;
//..
end;procedure TC.C;
begin
inherited;
//..
end;constructor TC.Create(Value: String);
begin
C_Str := Value;
end;destructor TC.Destroy;
begin
//..
inherited;
end;end.
to ihihonline(小小)
兄弟你理论讲了一大堆, 不好意思你跟我执行一下, 你能通过你就可以到Borland工作了
procedure hello(); virtual; abstract;
procedure TForm1.Button2Click(Sender: TObject);
begin
m1.hello;
end;不好意思,试问一下,procedure hello(); virtual; abstract;//你如何来实现呢?那么my1.hello又将从那儿来呢?我不知道您到底想说明什么问题,如果您觉的procedure hello(); virtual; abstract;也可以被完全的实现的话,是不是有点太那个了?
如果您想要的是Procedure Hello() ; virtual又何尝不可以呢?您可以试着运行下边的程度。unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type TA = Class
Public
Procedure A ; virtual ;
Procedure B ; Virtual ;
Procedure C ; virtual ;
end; TB = Class(TA)
Private
B_Str : String;
Public
Constructor Create(Value : String);
Destructor Destroy();override;
{这是覆盖。设么地方可以用override?当他积累相对应的方法是虚拟的或是动态的时候才可以用override}
Procedure A ; override;
Procedure B ; override;
Procedure C ; override;
end; TC = Class(TA)
Private
C_Str : String;
Public
Constructor Create(Value : String);
Destructor Destroy();override;
Procedure A ; override;
Procedure B ; override;
Procedure C ; override;
end; TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Procedure Test(Const pA : TA);
Procedure Tests(Const pB : TB);
end;var
Form1: TForm1;implementation{$R *.dfm}{TA}procedure TA.A;
begin
ShowMessage('TA-A');
end;procedure TA.B;
begin
ShowMessage('TA-B');
end;procedure TA.C;
begin
ShowMessage('TA-C');
end;{ TB }procedure TB.A;
begin
inherited;
//。。
ShowMessage('TC' + B_Str);
end;procedure TB.B;
begin
inherited;
//..
ShowMessage('TB' + B_Str);
end;procedure TB.C;
begin
inherited;
//..
end;constructor TB.Create(Value: String);
begin
//..
end;destructor TB.Destroy;
begin
//..
inherited;
end;{ TForm1 }procedure TForm1.Test(const pA: TA);
begin
pa.A;
end;procedure TForm1.Button1Click(Sender: TObject);
var
vTC : TC;
begin
vTC := TC.Create('多态实例_vTC');
Test(vTC);
vTC.Free;
end;procedure TForm1.Tests(const pB: TB);
begin
TB.Create('aaa');
pb.A;
end;{ TC }procedure TC.A;
begin
inherited;
//..
ShowMessage('a');
end;procedure TC.B;
begin
inherited;
//..
end;procedure TC.C;
begin
inherited;
//..
end;constructor TC.Create(Value: String);
begin
C_Str := Value;
end;destructor TC.Destroy;
begin
//..
inherited;
end;end.
不好意思,试问一下,procedure hello(); virtual; abstract;//你如何来实现呢?
也许我的表达能力有限, 但我只是想说明一个问题
procedure hello(); virtual;abstract;
它只是抽象方法只是为了说明我的子类有这种方法, 在自己并没有实现过程 拿个最通俗的例子吧 形状是祖先类, 有面积Area, 但你怎么实现它呢, 我肯定abstract,
但你要得到面积,肯定只有通过它的子类
正方开,圆形来实现它的Area来实现
我不敢苟同,
var a1:my1;
a2:my2;
begin
a1:=my1.Create;
a2:=my2.Create;
my1(a2).a; //你这只是强制转化,把a2 转为 my1, 那么它现在只是调用my1 的
// a 方法, 并没实现重载,
//对于类my2来说它已经是一个全新方法, 你自己可以用一个全局变量
//试验一下
a2.a;
end;
这点我同意,这不是多态的具体体现!多态其实就是实现了一种 "向上引用",而这种相上引用提体的具体地方我想您应该明白吧。父 = 子,就这!子有很,但我不管有多少,我只知道父有这么一个方法就可以了!是这样吗,我认为是。而所谓的后期绑定就是说,是不用进行这种转化直接可以去对其子进行等同的应用。----------------------------------------------------------
等待,如沙漠行舟,痛苦万分
procedure hello(); virtual;abstract;
它只是抽象方法只是为了说明我的子类有这种方法, 在自己并没有实现过程//////////////////////////////////////////
它的实现不就是子类的实现吗?它说明只是为了更多的引用到子类里边。再者,就您的所说的: 拿个最通俗的例子吧 形状是祖先类, 有面积Area, 但你怎么实现它呢, 我肯定abstract,
但你要得到面积,肯定只有通过它的子类
正方开,圆形来实现它的Area来实现///////////////////////
我觉的这个话题才是回到了多态上!这样才会产生上引用!而产生了这种向上引用才正真的产生了多态,难道这一点上我们有争议?多态就是把父和子模糊化了,对吗?而且是晚期的绑定。----------------------------------------------------------
等待,如沙漠行舟,痛苦万分
////引用
{begin Delphi中一个很容易混淆的概念就是重载和覆盖:重载可以实现多态,而多态是面向对象三个特性中最最重要的一个;而对于覆盖(override)只是一种简单的语法现象,和面向对象没有任何的关系。end }这段话好像有错误呀。-----------------------------------------------------------------------俺拿俺追求未来老婆的结果输赢和你赌,这个话要是有半点错误,我就上普驼山阿米托福!!!!
to ihihonline(小小)
兄弟你理论讲了一大堆, 不好意思你跟我执行一下, 你能通过你就可以到Borland工作了
procedure hello(); virtual; abstract;
procedure TForm1.Button2Click(Sender: TObject);
begin
m1.hello;
end;
-------------------------------------------------------------------------
我认为是回复人理解错小小的意思了,原因很简单,小小爱说废话,哈哈........无论是虚拟方法还是抽象方法,目的都是为了最终实现多态。但作为抽象方法,还有一个很明显的目的就是要给代码架设一个框架,而具体的实现都是在子类中完成的。因此,上面这个回复中的代码应该是无法通过的(嘿嘿,我没有试验过..........)
重载可以实现多态,我不明白。
重载是什么:同名不同参数
多态是什么:晚绑定,同名同参数(类型,数量)
重载是如何实现多态的?
覆盖(override),覆盖是什么?
请指教,谢谢。
to:FrameSniper(凤凰是否真的能够涅磐?)
重载可以实现多态,我不明白。
重载是什么:同名不同参数
多态是什么:晚绑定,同名同参数(类型,数量)
重载是如何实现多态的?
覆盖(override),覆盖是什么?
请指教,谢谢。
////////
这儿的确可能是你理解错了
你可以写点代码验证一下。
----------------------------------------------------------
等待,如沙漠行舟,痛苦万分
重载可以实现多态,我不明白。
重载是什么:同名不同参数
多态是什么:晚绑定,同名同参数(类型,数量)
重载是如何实现多态的?
覆盖(override),覆盖是什么?
请指教,谢谢。不是说重载可以实现多态,重载只是实现多态的方式而已。多态只是一种特性,但特性肯定也是通过一定的方式实现后来体现的,而重载就是这种方式。重载实际上就是通过一个指示字来告诉Delphi的编译器,现在你看到的这个方法在子类中是被扩展的,而且这种扩展可以通过向上引用来直接获取到..........其实至于参数那些东西只不过是一个表象而已,晚绑定也只是说编译器处理时间而已,这些东西都是多态的一些特点.........我认为没有必要一味的在这些概念上纠缠吧。你可以看看我上面说的关于向上引用的概念和向上引用为什么是安全的,以及反之为什么向下引用就不一定是安全的,对于理解多态的实质很有好处!
小小 中间一次回复 已经很好了 可能 有点厂 不过还请大家仔细看一下
再回帖 不要误解小小的意思 fs 这几天回帖这么多 不爱美人爱江山了 吼 吼 ~~
补充一个:
方法超载
type
t1=class(tobject)
procedure test(i:integer);overload;virtual;
end;
t2=class(t1)
procedure test(s:string);reintroduce;overload;
end;
呵呵,这个和覆盖的区别我清楚了。谢谢所有参与本帖的朋友。
重载实际上就是通过一个指示字来告诉Delphi的编译器,现在你看到的这个方法在子类中是被扩展的,而且这种扩展可以通过向上引用来直接获取到..........
--------------------------------------------------------------呵呵,在派生类中不加重载(overload)指示字的话,派生类的方法将屏蔽掉基类中的。
其实override就是一个关键字。一种对虚函数的操作。一种手段,来实现多态性。多态性就是多态性。就是手段和结果的联系。就像锤子钉钉子,来做家具一样。锤子和钉子和家具没有任何关系。
1.为什么my2中的procedure a自动重载了my1中的procedure
到底有没有重载,看看就知道了
var a1:my1;
a2:my2;
begin
a1:=my1.Create;
a2:=my2.Create;
my1(a2).a; //'my1-a'
a2.a; //'my2-a'
end;
===============================================================
可能是我懒的原因,我想说的其实是这样
引用:
=====================================================================
回复人: DWGZ() ( ) 信誉:100 2003-07-24 09:15:00 得分:0
1. my2 procedure a 并没有重载 my 的 procedure a, 它已经是已my1没有任何关系的新函数了……
============================================================================
我就是想说他并没实现重载,
爱翔,你的话是大错特错,Override和多态没有任何的关系!!!!!!!!更和什么虚函数没有任何的关系!!!!!!!!
var a1:my1;
a2:my2;
begin
a1:=my1.Create;
a2:=my2.Create;
my1(a2).hello; //'my2-hello'
a2.hello; //'my2-hello'
end;
=======================================================================my1(a2).hello; //'my2-hello'因为hello已经被重载了,
少写了几句话而已,:)
而不是 “高手,我要代码 ” “大虾,救命”这样的气氛
overload 是对于同级来说的,
override 是对于上下级来说的, 说白了就是替换或者叫重置,
TA = class
procedure P;
end; TAa = class(TA)
procedure p; overload;//这里加不加overload一个样
end;procedure TA.P;
begin
showmessage('基类TA的方法');
end;procedure TAa.P;
begin
showmessage('派生类TAa的方法');
end;procedure TForm1.Button1Click(Sender: TObject);
var
obj1: TA;
obj2: TAa;
begin
obj1 := TA.Create;
obj1.P;//结果是“基类TA的方法'”
obj1.Free; obj2 := TAa.Create;
obj2.P;//结果是“基类TAa的方法'”
obj2.Free;
end;