打印本文 打印本文 关闭窗口 关闭窗口
Delphi对象模型(Part II)
作者:武汉SEO闵涛  文章来源:敏韬网  点击数1843  更新时间:2009/4/23 18:42:51  文章录入:mintao  责任编辑:mintao
来决定可以调用的方法。与编译期间直接指定一个特定的方法的实现不同的是,编译器根据对象的实际类型存放一个间接的对方法的引用。运行期间,程序在类的运行期表(特别是VMT)中查找方法,然后调用实际的类型的方法。对象的真正的类必须是在编译期中声明的类,或者它的一个派生的类——这一点不成问题,因为VMT提供了指向正确的方法的指针。

要声明一个虚方法,可以在基类中使用vritual指示符,然后使用override指示符以在派生的类中提供该方法的新的定义。与Java不同的是,Delphi中方法在缺省情况下是静态的,因此你必须使用virtual指示符来声明一个虚方法。与C++不同的是,Delphi中要在派生类中覆盖一个虚方法必须使用override指示符。

2-5 使用虚方法。

2-5 绑定虚方法

type
  TAccount = class
  public
    procedure Withdraw(Amount: Currency); virtual;
  end;
  TSavingsAccount = class(TAccount)
  public
    procedure Withdraw(Amount: Currency); override;
  end;
var
  Savings: TSavingsAccount;
  Account: TAccount;
begin
  ...
  Savings.Withdraw(1000.00);     // 调用TSavingsAccount.Withdraw
  Account := Savings;
  Account.Withdraw(1000.00);     // 调用TSavingsAccount.Withdraw

除了vritual指示符,你还可以使用dynamic指示符。两者语义相同的,但实现不同。在VMT中查找一个虚方法很快,因为编译器在VMT中建了索引。而查找一个动态方法慢一些。调用一个动态方法虚要在动态方法表(DMT)中进行线性查找。在祖先类中查找直到遇到TObject或者该方法被找到为止。在某些场合,动态方法占用比虚方法更少的内存。除非要写一个VCL的替代物,否则你应当使用虚方法而不是动态方法。参见第三章以详细了解有关内容。

虚方法和动态方法可以在声明时使用abstract指示符,这样该类就不必给出对该方法的定义,但在派生的类中必须覆盖(override)该方法。C++中抽象方法的术语称为“纯虚方法”。当你调用一个包含有抽象方法的类的构造函数时, Delphi将给出编译警告,提示你可能有个错误。可能你要创建的是覆盖(override)并且实现了该抽象方法的派生类的一个实例。定义了一个或者多个抽象方法的类通常称为抽象类,尽管有些人认定该术语只适用于只定义了抽象方法的那些类。

提示:
当你构建一个自其他抽象类继承而来的抽象类时,你应当使用override和abstract指示符将所有的抽象方法重新声明。Delphi并没有要求这么做,因这只是个惯例。这些声明将清楚地告诉代码维护人员有哪些方法是抽象的。否则,维护人员可能对那些方法需要实现而那些方法需要保持抽象感到疑惑。例如:

type
  TBaseAbstract = class
    procedure Method; virtual; abstract;
  end;
  TDerivedAbstract = class(TBaseAbsract)
    procedure Method; override; abstract;
  end;
  TConcrete = class(TDerivedAbstract)
    procedure Method; override;
  end; 

类方法或构造器也可以是虚拟的。在Delphi中,类引用是一个真的实体,你可以将它赋值给一个变量,当作参数传递,或用作引用来调用类方法。如果构造器是虚拟的,则类引用有一个静态的基类类型,但你可以将一个派生类型的类引用赋值给它。Delphi将在该类的VMT中查找虚拟构造器,而后调用派生类的构造器。,

方法(以及其他函数和过程)可以被重载,也就是说,多个例程可以有相同的名字,但是参数定义必须各不相同。声明重载方法使用overload指示符。在派生类中可以重载继承于基类的方法。这种情况下,只有派生的类才需要使用overload指示符。毕竟,基类的作者不可能预见其他的程序员何时需要重载一个继承的方法。如果派生类中没有使用overload指示符,则基类中的相同名称的方法被屏蔽。如例2-6所示。

例子2-6:方法的重载

type
  TAuditKind = (auInternal, auExternal, auIRS, auNasty);
  TAccount = class
  public
    procedure Audit;
  end;
  TCheckingAccount = class(TAccount)
  public
    procedure Audit(Kind: TAuditKind); // Hides TAccount.Audit
  end;
  TSavingsAccount = class(TAccount)
  public
    // Can call TSavingsAccount.Audit and TAccount.Audit
    procedure Audit(Kind: TAuditKind); overload;
  end;
var
  Checking: TCheckingAccount;
  Savings: TSavingsAccount;
begin
  Checking := TCheckingAccount.Create;
  Savings := TSavingsAccount.Create;
  Checking.Audit;             // 错误,因为TAccount.Audit被屏蔽了。
  Savings.Audit;              //正确,因为Audiot被重载了。
  Savings.Audit(auNasty);     //正确
  Checking.Audit(auInternal);//正确
 
  PartI
  PartIII 
 

上一页  [1] [2] 

打印本文 打印本文 关闭窗口 关闭窗口