来自: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的区别,你可以看帮助,有什么不明白的,再说。
 
 

解决方案 »

  1.   

    执行这段代码,就能发现区别:
    var
      a: TBase;a := TDrivered.Create;
    a.base_not_virtual; //应该执行了TBase.base_not_virtual
    a.base_is_virtual; //应该执行了TDrivered.base_is_virtual
    这就是多态的特点。
      

  2.   

    但是我如果都加上  inherited;則完全一樣.
    我實在看不出virtual有什麼用處.
      

  3.   

    TBase里的两个方法有具体代码实现吗?在里面写一些不同的代码,你自然就会发现差别了
      

  4.   

    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;{ 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;
      

  5.   

    你这样当然没有区别。区别只能在这里:
    var
          a:  TBase;
      
      a  :=  TDrivered.Create;
      a.base_not_virtual;  //应该执行了TBase.base_not_virtual
      a.base_is_virtual;  //应该执行了TDrivered.base_is_virtual
      

  6.   

    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
      

  7.   

    但你用到overload时,你就知道区别了!
      

  8.   

    多态性的含义其实就是允许你用一个基类的变量在运行时态根据这个基类变量的具体子类类型调用相应子类的虚方法(一定得是虚方法)。打个比方:我有一个基类“哺乳动物”,它下面有多个子类“人”,“狗”,“鸟”,这时我就可以通过多态性实现用一个基类变量分别根据它的具体运行时类型(可能是人,可能是狗,也可能是鸟)来调用相应的行走方法(人是两条腿走路、狗是四条腿,鸟只会飞),这个行走方法必须得是虚方法,否则不行。不同就表现在不同子类之间。你的程序中只有一个子类,又都调用了inherited;又怎么会有不同呢?我也看不出有用虚方法的必要。
      

  9.   

    a.base_not_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] //调用虚方法表中的第一项存放的函数地址
     
    这可看到调用方式明显就不一样    
    正是由于这种调用方式才产生了多态
      

  10.   

    xzgyb(老达摩) 真不简单!用delphi都用到了汇编这个级别,看来我真是太菜了。
    xzgyb(老达摩),你上面的帖子里的东西太深奥了,可以推荐本书来看看吗?
      

  11.   

    smileofmoon,呵呵
    我都被你夸晕了
    我才是菜,只是喜欢瞎看
    就是什么也弄不出来上面的那个我就是看CPU窗口的,也没什么了
    其实看看这个汇编的东西
    对于了解系统的背后的东西很有好处,
      

  12.   

    感謝各位,我有點明白了,請看以下我理解的是否正確:
      當祖先類使用了一個方法,這個方法可能在子類中被修改,並且祖先類要使用修改後的方法時,將這個方法虛擬化.
      當祖先類使用的方法是靜態的(不需要更改).這個時候方法不虛擬化.
      例如: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方法
      

  13.   


    区别只能在这里:
      var
                  a:    TBase;
          
          a    :=    TDrivered.Create;
          a.base_not_virtual;    //应该执行了TBase.base_not_virtual
          a.base_is_virtual;    //应该执行了TDrivered.base_is_virtual
      
      

  14.   

    虚拟方法是多态性函数(polymorphic function)
    是为了实现多态性,多态是类型论中的概念,
    有其复杂的数学背景。在存在多态的语言里面,类型可以演算,即在程序中动态确定,
    编译期间无法确定类型演算的结果,(就如,无法确定1+1的结果一样)与类型所匹配的函数只能动态绑定,在运行的时候查虚拟函数表(VMT)
    静态方法(和c++中的static方法不是一个概念)不用查表,编译器就可以
    确定!(这是最直观的区别)但是事情不是绝对的,在一些语言中,由于类型系统设计的比较完善
    在编译期间就可以完成 类型推断,所以这些语言中的多态就不需要
    虚函数。本来想引用一本类型论书上的原话,但是很多符号(用于类型演算的)
    无法显示。只能作罢。不过大家可以明白,多态是有着复杂的数学背景的。