打印本文 打印本文 关闭窗口 关闭窗口
Delphi对象模型(Part III)
作者:武汉SEO闵涛  文章来源:敏韬网  点击数1438  更新时间:2009/4/23 18:42:51  文章录入:mintao  责任编辑:mintao

 

Delphi对象模型 (PART III)

 

 

Delphi对于面向对象编程的支持丰富而且强大。除了传统的类和对象,Delphi还提供了接口,异常处理,多线程编程等特性。这一章节深入讲解了Delphi的对象模型。读者应当对标准的Pascal比较熟悉,并且对有关面向对象编程的基本法则有一定了解。

(本文的英文原文将Delphi与Object Pascal统一表述为Delphi,可能有概念不清之嫌疑。但在大多数情况下,相信读者能够根据上下文来判定文中所述之Delphi的具体含义——译者注。)

 

构造器(Constructor)

每一个类都有一个或多个可能是自基类继承而来的构造器。按照惯例,构造器通常命名为Create,但你也可以使用其他名称。有些构造器以Create打头,为了传递更多的信息,被命名为诸如CreateFromFile或者CreateFromStream这样的名字。通常情况下,使用”Create” 这个名字就可以了,因为你可以使用重载来定义多个相同名字的构造器。另一个原因是为了保持与C++Builder的兼容。因为C++不允许构造器使用不同名称,因此你必须使用重载来定义多个构造器。

调用构造器

构造器是对象方法和类方法的混合体。你可以使用一个对象引用或者一个类引用来调用它。Delphi会传递一个附加的隐含的参数来指示它如何被调用。假如使用一个类引用来调用构造器,Delphi会调用类的NewInstance方法以获得该类的一个新的实例。然后,构造器继续处理并且初始化对象。构造器自动引入一个try-except模块,当构造器中触发异常时,Delphi将自动调用析构器。

使用对象引用来调用构造器时,Delphi不会引入try-except块,也不会调用NewInstance方法。相反,它象调用普通方法一样调用构造器。这个特性允许你调用继承的构造器而无需增加额外的内存开销。

提示
一个常见的错误是尝试使用对象引用来创建一个对象,而不是用一个类引用来创建对象并将它赋值给一个对象引用:

var
  Account: TSavingsAccount;
begin
  Account.Create;                    //错误
  Account := TSavingsAccount.Create; //正确

Delphi的特性之一是你可以控制在何时调用,如何调用,以及是否需要调用一个继承的构造器。这个特性使你可以构建功能强大的类,但在一定程度上也使得错误容易发生。

Delphi总是先构造派生的类,仅当派生类调用了继承的构造器时才去构造基类。在C++中次序相反,从祖先类开始构建,最后才是派生的类。因而,假如有类C继承于B,而B继承于A,那么Delphi先是构建C,然后是B最后是A.C++先构建A,然后B,最后C。

虚方法和构造器

另一个介于C++和Delphi之间的一个很大的不同是,在C++中,构造器总是根据已经被创建的类的虚方法表来运行。而在Delphi中,虚方法代表了所有派生类的内容,即使基类还没有被创建。因此,当你书写一个可能被构造器调用的虚方法时一定要小心。否则,对象可能还没有完全创建时该方法就被调用了。为了预防这种情况,你应当覆盖AfterConstruction方法,在其中填写需要等到对象被完全创建后才能执行的代码。假如要覆盖AfterConstruction,别忘了调用inherited方法。

一个构造器可以调用另一个构造器。Delphi能够区分该调用是否来自于对象引用,因此调用构造器与调用普通方法相同。调用另一个构造器最常见的理由是把初始化代码放在一个单一的构造器中。例2-7显示了声明和调用构造器的几种不同的方法。

2-7:声明和调用构造器

type
  TCustomer = class ... end;
  TAccount = class
  private
    fBalance: Currency;
    fNumber: Cardinal;
    fCustomer: TCustomer;
  public
    constructor Create(Customer: TCustomer); virtual;
    destructor Destroy; override;
  end;
  TSavingsAccount = class(TAccount)
  private
    fInterestRate: Integer; // Scaled by 1000
  public
    constructor Create(Customer: TCustomer); override; overload;
    constructor Create(Customer: TCustomer; InterestRate: Integer);
        overload;
//注意:TSaveingAccount不需要再定义一个析构器。
//它只是简单的继承了TAccount的构造器
    
  end;
 
var
  AccountNumber: Cardinal = 1;
 
constructor TAccount.Create(Customer: TCustomer);
begin
  inherited Create;             // Call TObject.Create.
  fNumber := AccountNumber;     // Assign a unique account number.
  Inc(AccountNumber);
  fCustomer := Customer;        // Notify customer of new account.
  Customer.AttachAccount(Self);
end;
 
destructor TAccount.Destroy;
begin
  
  //如果在设置fCustomer字段之前构造出错,则该字段为nil。
//仅当Customer不为nil才释放account。
  if Customer <> nil then
    Customer.ReleaseAccount(Self);
  //调用TObject.Destroy.
  inherited Destroy;
end;
 
const
  DefaultInterestRate = 5000;  // 5%, scaled by 1000
 
constructor TSavingsAccount.Create(Customer: TCustomer);
begin
  //调用同类的另一个构造器
  Create(Customer, DefaultInterestRate);
end;
 
constructor TSavingsAccount(Customer: TCustomer; InterestRate:Integer);
begin
  //调用TAccount.Create
  inherited Create(Customer);
  fInterestRate := InterestRate;
end;

析构器(Destructor)

析构器和构造器一样也隐藏了一个附加的参数。第一次调用时,该附加参数被置为True。这使得Delphi调用FreeInstance来释放对象。如果该析构器调用了继承的析构器,那么Delphi将这个隐含的参数设置为False以防止继承的析构器再次释放同一个对象。

[1] [2]  下一页

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