来自:sun77wind, 时间:2002-2-27 11:26:00, ID:945607
看这个例子,摘自Delphi Help。
你的例子当然不能说明。
type
TFigure = class
procedure Draw; virtual;
end;
TRectangle = class(TFigure)
procedure Draw; override;
end;
TEllipse = class(TFigure)
procedure Draw; override;
end;Given these declarations, the following code illustrates the effect of calling a virtual method through a variable whose actual type varies at runtime.var
Figure: TFigure;
begin
Figure := TRectangle.Create;
Figure.Draw; // calls TRectangle.Draw
Figure.Destroy;
Figure := TEllipse.Create;
Figure.Draw; // calls TEllipse.Draw
Figure.Destroy;
end;
明白否?
来自:ugvanxk, 时间:2002-2-27 11:27:00, ID:945611
var a: tbase;
begin
a:=tdrivered.create;
a.base_not_virtual;//调用 tabse
tdrivered(a).base_not_virtual;//调用 tdrivered
procedure base_is_virtual;override;
如果没有 inherited;//你看结果
来自:rk_kitty, 时间:2002-2-27 11:42:00, ID:945650 | 编辑
to sun77wind:
我把這個程序的virtual,override全部刪除,結果還是一樣.
Figure.Draw; // calls TRectangle.Draw
Figure.Draw; // calls TEllipse.Draw
那我為什麼要用virtual,override.
来自:天真, 时间:2002-2-27 11:48:00, ID:945663
gz
来自:Sindbad, 时间:2002-2-27 12:02:00, ID:945696
简单地讲,为了代码重用。
建议你看看关于OOP编程的书。
来自:redsky.l, 时间:2002-2-27 12:09:00, ID:945705
打字练练: Static 对象类型中方法的默认属性——静态 对于静态方法,不必再用标识符来指明它的属性。当调用静态方法时,从变量本身的类
型就可决定运行哪个过程方法。
当编译器遇到AnObject.AStaticMethod的引用时,其中,AnObject是AClass Type 类
的一个变量,则产生调用AClass.AStaticMethod的代码,或者产生调用AClass Type继承来
的AStaticMethod的代码。 Virtual
与静态方法调用相反,虚拟方法调用关不由编译器立即决定。该运行的实际过程主法是
运行时确定的。称为后期绑定。在类成只中可以在任何一方法定义后面加上Virtual。
当引用虚拟方法时,要通过变量所代表的的实际类型来确定该调用哪个过程。造成这种
差别的原因是子孙类可能覆盖它由父类中继承来的虚拟方法。虚拟方法的变化也将被继承下
去。
来自:sun77wind, 时间:2002-2-27 13:29:00, ID:945995
结果不应该是一样的,
var
Figure: TFigure;//虽然Figure都是TFigure类
begin
Figure := TRectangle.Create;//但是创建的子类不同
Figure.Draw; // 调用的 TRectangle.Draw函数,画出的Rectangle
Figure.Destroy;
Figure := TEllipse.Create;
Figure.Draw; // 调用的是 TEllipse.Draw,画出的是Ellipse,应该和上一个有不同的结果。
Figure.Destroy;
end;
从实际中来讲,因为Rectangle(长方形)和Ellipse(椭圆形)都是图形,这是共同点,
所以我们定义一个Figure类,来存放共有的属性和方法,子类(具体的图形,如长方形等)
来做不同的事情---长方形有长方形的画法,椭圆形有椭圆形的画法。
同意Sindbad, 你去看看有关OOP的东西吧。
来自:rk_kitty, 时间:2002-2-27 13:37:00, ID:946028 | 编辑
to sun77wind
對不起,我說錯了.
我的意思是用不用虛擬方法都是一樣的.
那不是說虛擬方法沒有意義了嗎?
来自:sun77wind, 时间:2002-2-27 13:41:00, ID:946052
至于使用virtual的问题,看这个例子
TFigure = class
procedure Draw;//不用virtual,是静态方法。
end;
TRectangle = class(TFigure)
procedure Draw;
end;var
Figure: TFigure;
Rectangle: TRectangle;
begin
Figure := TFigure.Create;
Figure.Draw; // calls TFigure.Draw
Figure.Destroy;
Figure := TRectangle.Create;
Figure.Draw; // calls TFigure.Draw
TRectangle(Figure).Draw; // calls TRectangle.Draw
Figure.Destroy;
Rectangle := TRectangle.Create;
Rectangle.Draw; // calls TRectangle.Draw
Rectangle.Destroy;
end;
关于静态Static,Virtual和dynamic的区别,你可以看帮助,有什么不明白的,再说。
看这个例子,摘自Delphi Help。
你的例子当然不能说明。
type
TFigure = class
procedure Draw; virtual;
end;
TRectangle = class(TFigure)
procedure Draw; override;
end;
TEllipse = class(TFigure)
procedure Draw; override;
end;Given these declarations, the following code illustrates the effect of calling a virtual method through a variable whose actual type varies at runtime.var
Figure: TFigure;
begin
Figure := TRectangle.Create;
Figure.Draw; // calls TRectangle.Draw
Figure.Destroy;
Figure := TEllipse.Create;
Figure.Draw; // calls TEllipse.Draw
Figure.Destroy;
end;
明白否?
来自:ugvanxk, 时间:2002-2-27 11:27:00, ID:945611
var a: tbase;
begin
a:=tdrivered.create;
a.base_not_virtual;//调用 tabse
tdrivered(a).base_not_virtual;//调用 tdrivered
procedure base_is_virtual;override;
如果没有 inherited;//你看结果
来自:rk_kitty, 时间:2002-2-27 11:42:00, ID:945650 | 编辑
to sun77wind:
我把這個程序的virtual,override全部刪除,結果還是一樣.
Figure.Draw; // calls TRectangle.Draw
Figure.Draw; // calls TEllipse.Draw
那我為什麼要用virtual,override.
来自:天真, 时间:2002-2-27 11:48:00, ID:945663
gz
来自:Sindbad, 时间:2002-2-27 12:02:00, ID:945696
简单地讲,为了代码重用。
建议你看看关于OOP编程的书。
来自:redsky.l, 时间:2002-2-27 12:09:00, ID:945705
打字练练: Static 对象类型中方法的默认属性——静态 对于静态方法,不必再用标识符来指明它的属性。当调用静态方法时,从变量本身的类
型就可决定运行哪个过程方法。
当编译器遇到AnObject.AStaticMethod的引用时,其中,AnObject是AClass Type 类
的一个变量,则产生调用AClass.AStaticMethod的代码,或者产生调用AClass Type继承来
的AStaticMethod的代码。 Virtual
与静态方法调用相反,虚拟方法调用关不由编译器立即决定。该运行的实际过程主法是
运行时确定的。称为后期绑定。在类成只中可以在任何一方法定义后面加上Virtual。
当引用虚拟方法时,要通过变量所代表的的实际类型来确定该调用哪个过程。造成这种
差别的原因是子孙类可能覆盖它由父类中继承来的虚拟方法。虚拟方法的变化也将被继承下
去。
来自:sun77wind, 时间:2002-2-27 13:29:00, ID:945995
结果不应该是一样的,
var
Figure: TFigure;//虽然Figure都是TFigure类
begin
Figure := TRectangle.Create;//但是创建的子类不同
Figure.Draw; // 调用的 TRectangle.Draw函数,画出的Rectangle
Figure.Destroy;
Figure := TEllipse.Create;
Figure.Draw; // 调用的是 TEllipse.Draw,画出的是Ellipse,应该和上一个有不同的结果。
Figure.Destroy;
end;
从实际中来讲,因为Rectangle(长方形)和Ellipse(椭圆形)都是图形,这是共同点,
所以我们定义一个Figure类,来存放共有的属性和方法,子类(具体的图形,如长方形等)
来做不同的事情---长方形有长方形的画法,椭圆形有椭圆形的画法。
同意Sindbad, 你去看看有关OOP的东西吧。
来自:rk_kitty, 时间:2002-2-27 13:37:00, ID:946028 | 编辑
to sun77wind
對不起,我說錯了.
我的意思是用不用虛擬方法都是一樣的.
那不是說虛擬方法沒有意義了嗎?
来自:sun77wind, 时间:2002-2-27 13:41:00, ID:946052
至于使用virtual的问题,看这个例子
TFigure = class
procedure Draw;//不用virtual,是静态方法。
end;
TRectangle = class(TFigure)
procedure Draw;
end;var
Figure: TFigure;
Rectangle: TRectangle;
begin
Figure := TFigure.Create;
Figure.Draw; // calls TFigure.Draw
Figure.Destroy;
Figure := TRectangle.Create;
Figure.Draw; // calls TFigure.Draw
TRectangle(Figure).Draw; // calls TRectangle.Draw
Figure.Destroy;
Rectangle := TRectangle.Create;
Rectangle.Draw; // calls TRectangle.Draw
Rectangle.Destroy;
end;
关于静态Static,Virtual和dynamic的区别,你可以看帮助,有什么不明白的,再说。
解决方案 »
- 如何用api函数来打印Timage
- 使用json-rpc实现delphi+java异构语言RPC调用
- SPCOMM控件做个例子却不好使,无法打开端口
- 我有一个CHAR类型的字段,请问如何对这个字段求和,急急!
- 为什么我用XML MAPPER 不能把XML 文件转换成.xtr 文件格式
- 关于多线程的一个问题,在线等,十万火急!!!
- 大家有知道亿阳信通的吗?偶要去,但不知道怎么样?请介绍。来者有分
- TreeView的小问题?
- 我想问三个很简单的问题,千万别笑我,因为我刚开始学.(我以前学vb的)
- 再次求救,大家帮小弟一把吧
- 100寻找winXP风格控件包下载。
- delphi游戏编程里有哪些方法实现全屏模式呢?
var
a: TBase;a := TDrivered.Create;
a.base_not_virtual; //应该执行了TBase.base_not_virtual
a.base_is_virtual; //应该执行了TDrivered.base_is_virtual
这就是多态的特点。
我實在看不出virtual有什麼用處.
TBase = Class
procedure base_is_virtual;virtual;
procedure base_not_virtual;
end;
TDerived = Class(TBase)
procedure base_is_virtual;override;
procedure base_not_virtual;
end;{ TDerived }procedure TDerived.base_is_virtual;
begin
inherited;
// ShowMessage('derived_msg virtual');
end;procedure TDerived.base_not_virtual;
begin
inherited;
// ShowMessage('Derived_Msg Not virtual');
end;{ TBase }procedure TBase.base_is_virtual;
begin
ShowMessage('base_msg virtual');
end;procedure TBase.base_not_virtual;
begin
ShowMessage('base_Msg Not virtual');
end;procedure TForm1.Button1Click(Sender: TObject);
var
a:TDerived;
begin
a := TDerived.Create;
a.base_is_virtual;
a.Free;
end;procedure TForm1.Button2Click(Sender: TObject);
var
a:TDerived;
begin
a := TDerived.Create;
a.base_not_virtual;
a.Free;
end;
var
a: TBase;
a := TDrivered.Create;
a.base_not_virtual; //应该执行了TBase.base_not_virtual
a.base_is_virtual; //应该执行了TDrivered.base_is_virtual
TBase = Class
procedure base_is_virtual;virtual;
procedure base_not_virtual;
end;
TDerived = class(TBase)
procedure base_is_virtual;override;
procedure base_not_virtual;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.DFM}{ TBase }procedure TBase.base_is_virtual;
begin
ShowMessage('base_is_virtual');
end;procedure TBase.base_not_virtual;
begin
ShowMessage('base_not_virtual');
end;{ TDerived }procedure TDerived.base_is_virtual;
begin
inherited;
ShowMessage('derived:base_is_virtual');
end;procedure TDerived.base_not_virtual;
begin
inherited;
ShowMessage('Derived:base_not_virtual');
end;procedure TForm1.Button1Click(Sender: TObject);
var
a:TDerived;
begin
a := TDerived.create;
a.base_not_virtual;
//執行了TDerived.base_not_virtual和TBase.Base_not_virtual;
a.base_is_virtual;
//執行了TDerived.base_is_virtual和TBase.Base_is_virtual;
a.Free;
end;
我還是看不出為什麼要用Virtual
//執行了TDerived.base_not_virtual和TBase.Base_not_virtual;
a.base_is_virtual;
两个的汇编代码如下:
a.base_not_virtualmov eax, ebx //ebx为保存的对象引用
call TDerived.base_not_virtuala.base_is_virtualmov eax, ebx
mov edx, [eax] //edx即为VPtr
call dword ptr[edx] //调用虚方法表中的第一项存放的函数地址
这可看到调用方式明显就不一样
正是由于这种调用方式才产生了多态
xzgyb(老达摩),你上面的帖子里的东西太深奥了,可以推荐本书来看看吗?
我都被你夸晕了
我才是菜,只是喜欢瞎看
就是什么也弄不出来上面的那个我就是看CPU窗口的,也没什么了
其实看看这个汇编的东西
对于了解系统的背后的东西很有好处,
當祖先類使用了一個方法,這個方法可能在子類中被修改,並且祖先類要使用修改後的方法時,將這個方法虛擬化.
當祖先類使用的方法是靜態的(不需要更改).這個時候方法不虛擬化.
例如:form1中有兩個方法:Is_Virtual(虛擬方法),IsNot_Virtual(非虛擬方法)
form1中的btnIs_virtual調用了Is_Virtual,btnIsNot_Virtual調用了IsNot_Virtual
form2從form1繼承而來,在form2中對Is_Virtual,IsNot_Virtual進行了修改,都使用了inherited
這時發現btnIs_Virtual調用了form1的Is_Virtual後還調用form2的IsVirtual方法
而btnIsNot_Virtual只調用了form1的IsNot_Virtual方法
区别只能在这里:
var
a: TBase;
a := TDrivered.Create;
a.base_not_virtual; //应该执行了TBase.base_not_virtual
a.base_is_virtual; //应该执行了TDrivered.base_is_virtual
是为了实现多态性,多态是类型论中的概念,
有其复杂的数学背景。在存在多态的语言里面,类型可以演算,即在程序中动态确定,
编译期间无法确定类型演算的结果,(就如,无法确定1+1的结果一样)与类型所匹配的函数只能动态绑定,在运行的时候查虚拟函数表(VMT)
静态方法(和c++中的static方法不是一个概念)不用查表,编译器就可以
确定!(这是最直观的区别)但是事情不是绝对的,在一些语言中,由于类型系统设计的比较完善
在编译期间就可以完成 类型推断,所以这些语言中的多态就不需要
虚函数。本来想引用一本类型论书上的原话,但是很多符号(用于类型演算的)
无法显示。只能作罢。不过大家可以明白,多态是有着复杂的数学背景的。