請用實例說明靜態方法與虛擬方法的區別.(200分)

  • 主题发起人 主题发起人 rk_kitty
  • 开始时间 开始时间
R

rk_kitty

Unregistered / Unconfirmed
GUEST, unregistred user!
type
TBase = class
protected
procedure base_not_virtual;
procedure base_is_virtual;virtual

end;
...
procedure TBase.base_not_virtual;
begin
//do something;
end;
procedure TBase.base_is_virtual;
begin
//do something;
end;

type
TDrivered = Class(TBase)
protected
procedure base_not_virtual;
procedure base_is_virtual;override;
end;
...
procedure TDrivered.base_not_virtual;
begin
inherited;
//do something;
end;
procedure TDrivered.base_is_virtual;
begin
inherited;
//do something;
end;
發現它們運行的結果完全相同.請大俠用實例說明在什麼情況下出現不同.

 
看这个例子,摘自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;
明白否?
 
var a: tbase;
begin
a:=tdrivered.create;
a.base_not_virtual;//调用 tabse
tdrivered(a).base_not_virtual;//调用 tdrivered
procedure base_is_virtual;override;
如果没有 inherited;//你看结果




 
to sun77wind:
我把這個程序的virtual,override全部刪除,結果還是一樣.
Figure.Draw
// calls TRectangle.Draw
Figure.Draw
// calls TEllipse.Draw
那我為什麼要用virtual,override.

 
简单地讲,为了代码重用。
建议你看看关于OOP编程的书。
 
打字练练:

Static 对象类型中方法的默认属性——静态

对于静态方法,不必再用标识符来指明它的属性。当调用静态方法时,从变量本身的类
型就可决定运行哪个过程方法。
当编译器遇到AnObject.AStaticMethod的引用时,其中,AnObject是AClass Type 类
的一个变量,则产生调用AClass.AStaticMethod的代码,或者产生调用AClass Type继承来
的AStaticMethod的代码。

Virtual

与静态方法调用相反,虚拟方法调用关不由编译器立即决定。该运行的实际过程主法是
运行时确定的。称为后期绑定。在类成只中可以在任何一方法定义后面加上Virtual。
当引用虚拟方法时,要通过变量所代表的的实际类型来确定该调用哪个过程。造成这种
差别的原因是子孙类可能覆盖它由父类中继承来的虚拟方法。虚拟方法的变化也将被继承下
去。
 
结果不应该是一样的,
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的东西吧。
 
to sun77wind
對不起,我說錯了.
我的意思是用不用虛擬方法都是一樣的.
那不是說虛擬方法沒有意義了嗎?
 
至于使用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的区别,你可以看帮助,有什么不明白的,再说。
 
。。。。。。。。。。。。。。。。。。。
 
type
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
 
上边除了REDSKYL1说的明白一些,其他人也恐怕也是没有说清楚。
对于你所举的例子来说,两者从实现的原理是不一样的(如REDSKYL所言),但结果是一样的。如果只是
简单用法而言,没有必要用virtual.但如果你写的是一个很庞大的东西,尤其如果要用到多态性
的时候,两者的结果和代码重用程度会是截然不同的。
以下是我在Win2k和D6下试验用的一段代码。希望对你有所启示。
新开一个窗体,放两个BUTTON.一个为:VIRTUAL,一个为:STATIC.
程序如下:
/////////////////////////////////////////
// File: Static and virtual method test block
// Project:
// Date:
// CopyRight (c) 2002 by xy
// E-Mail:xynet@163.com
////////////////////////////////////////
unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
btnVirtual: TButton;
btnStatic: TButton;
procedure btnVirtualClick(Sender: TObject);
procedure btnStaticClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TParent = class(TObject)
Procedure Method_No_Virtual;
Procedure Method_Is_Virtual;Virtual;
end;
TChild = class(TParent)
Procedure Method_No_Virtual;
Procedure Method_Is_Virtual;Override;
end;



var
Form1: TForm1;

implementation

{$R *.dfm}

{ TParent }

procedure TParent.Method_Is_Virtual;
begin
Showmessage('TParent.Method_Is_Virtual');
end;

procedure TParent.Method_No_Virtual;
begin
Showmessage('TParent.Method_No_Virtual');
end;

{ TChild }

procedure TChild.Method_Is_Virtual;
begin
inherited;//按CTRL+SHIFT+C自动生成该行
Showmessage('TChild.Method_Is_Virtual');
end;

procedure TChild.Method_No_Virtual;
begin
inherited;//按CTRL+SHIFT+C不会自动生成该行,需手工写
Showmessage('TChild.Method_No_Virtual');
end;

procedure Call_Method_Is_Virtual(o:TParent);
begin
o.Method_Is_Virtual;
end;
procedure Call_Method_No_Virtual(o:Tparent);
begin
o.Method_No_Virtual;
end;


procedure TForm1.btnVirtualClick(Sender: TObject);
var
Parent:TParent;
Child:TChild;
begin
Parent:=TParent.Create;
Child :=TChild.Create;
Call_Method_Is_Virtual(child)
//显示:TParent.Method_Is_Virtual 和TChild.Method_Is_Virtual
//Call_Method_Is_Virtual(parent);//显示:TParent.Method_Is_Virtual
Child.Free;
Parent.Free;
end;

procedure TForm1.btnStaticClick(Sender: TObject);
var
Parent:TParent;
Child:TChild;
begin
Parent:=TParent.Create;
Child :=TChild.Create;
Call_Method_NO_Virtual(child)
//显示:TParent.Method_No_Virtual
//Call_Method_No_Virtual(parent)
//显示:TParent.Method_No_Virtual
Child.Free;
Parent.Free;

end;

end.
 
感謝各位,我終於有點感覺了
 
to:xynet
我叫:redsky.L 不是 redsky1 [:)]
 
后退
顶部