ived classes must override that method. The C++ term for an abstract method is a "pure virtual method." If you call a constructor for a class that has an abstract method, the compiler issues a warning, telling you that you probably made a mistake. You probably wanted to create an instance of a derived class that overrides and implements the abstract method. A class that declares one or more abstract methods is often called an abstract class, although some people reserve that term for a class that declares only abstract methods.
TIP: If you write an abstract class that inherits from another abstract class, you should redeclare all abstract methods with the override and abstract directives. Delphi does not require this, but common sense does. The declarations clearly inform the maintainer of the code that the methods are abstract. Otherwise, the maintainer must wonder whether the methods should have been implemented or should have remained abstract. For example: type
TBaseAbstract = class
procedure Method; virtual; abstract;
end;
TDerivedAbstract = class(TBaseAbsract)
procedure Method; override; abstract;
end;
TConcrete = class(TDerivedAbstract)
procedure Method; override;
end;
A class method or constructor can also be virtual. In Delphi, class references are real entities that you can assign to variables, pass as parameters, and use as references for calling class methods. If a constructor is virtual, a class reference can have a static type of the base class, but you can assign to it a class reference for a derived class. Delphi looks up the virtual constructor in the class''''s VMT and calls the constructor for the derived class.
Methods (and other functions and procedures) can be overloaded, that is, multiple routines can have the same name, provided they take different arguments. Declare overloaded methods with the overload directive. A derived class can overload a method it inherits from a base class. In that case, only the derived class needs the overload directive. After all, the author of the base class cannot predict the future and know when other programmers might want to overload an inherited method. Without the overload directive in the derived class, the method in the derived class hides the method in the base class, as shown in Example 2-6.
Example 2-6: Overloading Methods 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; // Error because TAccount.Audit is hidden
Savings.Audit; // Okay because Audit is overloaded
Savings.Audit(auNasty); // Okay
Checking.Audit(auInternal); // Okay
Constructors
Every class has one or more constructors, possibly inherited from a base class. By convention, constructors are usually named Create, although you can use any name you like. Some constructor names start with Create, but convey additional information, such as CreateFromFile or CreateFromStream. Usually, though, the simple name Create is sufficient, and you can use method overloading to define multiple constructors with the same name. Another reason to overload the name Create is for compatibility with C++ Builder. C++ does not permit different constructor names, so you must use overloading to define multiple constructors.
Calling a constructor
A constructor is a hybrid of object and class methods. You can call it using an object reference or a class reference. Delphi passes an additional, hidden parameter to indicate how it was called. If you call a constructor using a class reference, Delphi calls the class''''s NewInstance method to allocate a new instance of the class. After calling NewInstance, the constructor continues and initializes the object. The constructor automatically sets up a try-except block, and if any exception occurs in the constructor, Delphi calls the destructor.
When you call a constructor with an object reference, Delphi does not set up the try-except block and does not call NewInstance. Instead, it calls the constructor the same way it calls any ordinary method. This lets you call an inherited constructor without unnecessary overhead.
TIP: A common error is to try to create an object by calling a constructor with an object reference, rather than calling it with a class reference and assigning it to the object variable: var
Account: TSavingsAccount;
begin
Account.Create; // wrong
Account := TSavingsAccount.Create; // right
One of Delphi''''s features is that you have total control over when, how, and whether to call the inherited constructor. This lets you write some powerful and interesting classes, but also introduces an area where it is easy to make mistakes.
Delphi always constructs the derived class first, and only if the derived class calls the inherited constructor does Delphi construct the base class. C++ constructs classes in the opposite direction, starting from the ancestor class and constructing the derived class last. Thus, if class C inherits from B, which inherits from A, Delphi constructs C first, then B, and A last. C++ constructs A first, then B, and finally C.
Virtual methods and constructors
Another significant difference between C++ and Delphi is that in C++, a constructor always runs with the virtual method table of the class being constructed, but in Delphi, the virtual methods are those of the derived class, even when the base class is being constructed. As a result, you must be careful when writing any virtual method that might be called from a constructor. Unless you are careful, the object might not be fully constructed when the method is called. To avoid any problems, you should override the AfterConstruction method and use that for any code that needs to wait until the object is fully constructed. If you override AfterConstruction, be sure to call the inherited method, too.
One constructor can call another constructor. Delphi can tell the call is from an object reference (namely, Self), so it calls the constructor as an ordinary method. The most common reason to call another constructor is to put all the initialization code in a single constructor. Example 2-7 shows some different ways to define and call constructors.
Example 2-7: Declaring and Calling Constructors 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;
// Note that TSavingsAccount does not need a destructor. It simply
// inherits the destructor from 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
// If the constructor fails before setting fCustomer, the field
// will be nil. Release the account only if Customer is not nil.
if Customer <> nil then
Customer.ReleaseAccount(Self);
// Call TObject.Destroy.
inherited Destroy;
end;
const
DefaultInterestRate = 5000; // 5%, scaled by 1000
constructor TSavingsAccount.Create(Customer: TCustomer);
begin
// Call a sibling constructor.
Create(Customer, DefaultInterestRate);
end;
constructor TSavingsAccount(Customer: TCustomer; InterestRate:Integer);
begin
// Call TAccount.Create.
inherited Create(Customer);
fInterestRate := InterestRate;
end;
Destructors
Destructors, like constructors, take an extra hidden parameter. The first call to a destructor passes True for the extra parameter. This tells Delphi to call FreeInstance to free the object. If the destructor calls an inherited destructor, Delphi passes False as the hidden parameter to prevent the inherited destructor from trying to free the same object.
TIP: A class usually has one destructor, called Destroy. Delphi lets you declare additional destructors, but you shouldn''''t take advantage of that feature. Declaring multiple destructors is confusing and serves no useful purpose.
Before Delphi starts the body of the destructor, it calls the virtual method, BeforeDestruction. You can override BeforeDestruction to assert program state or take care of other business that must take place before any destructor starts. This lets you write a class safely without worrying about how or whether any derived classes will call the base class destructor.
TIP: When writing a class, you might need to override the Destroy de 上一页 [1] [2] [3] [4] [5] 下一页 [系统软件]InstallShield Express for delphi制作安装程序定… [系统软件]The GRETA Regular Expression Template Archive [系统软件]OLE with the internet explorer [系统软件]14.5.10.1 Object creation expressions [常用软件]InstallShield Express制作Delphi数据库安装程序 [常用软件]Firefox: What’s the next step? [VB.NET程序]VB.Net中文教程(8) 对象(Object)基本概念 [VB.NET程序]The UDPChat Source(VB.NET) [Delphi程序]为什么选择Delphi.Net ? [Delphi程序]《关于VisiBroker For Delphi的使用》(4)
|