Delphi Object Model (Part III)
Delphi is rich and powerful for object-oriented programming. In addition to traditional classes and objects, Delphi also provides features such as interface, abnormal processing, multi-threaded programming. This chapter explains the object model of Delphi. The reader should be familiar with the standard Pascal and have a certain understanding of the basic law on object-oriented programming.
(The original text of this article will decompose Delphi and Object Pascal as Delphi, may have a conceptual suspected. However, in most cases, I believe that readers can determine the specific meaning of Delphi described in the text according to context - Translator's Note .)
Constructor
Each class has one or more constructors that may be inherited from the base class. According to conventions, constructors are typically named CREATE, but you can also use other names. Some constructors are headed by Create, in order to pass more information, named such as CreateFromFile or CreateFromstream. Typically, you can use the name of "CREATE" because you can use the overload to define a constructor of multiple identical names. Another reason is to keep compatibility with C Builder. Because C does not allow constructors to use different names, you must use overload to define multiple constructors.
Call constructor
The constructor is a mixture of an object method and a class method. You can use an object reference or a class reference to call it. Delphi communicates an additional implicit parameter to indicate how it is called. If a class reference is used to call the constructor, the Delphi will call the NEWINSTANCE method of the class to obtain a new instance of the class. Then, the constructor continues to process and initializes the object. The constructor automatically introduces a Try-Except module that when the exception is triggered in the constructor, Delphi will automatically call the destructor.
When using an object reference to call the constructor, Delphi does not introduce the TRY-ExcePt block, nor does the newinstance method. Instead, it calls the constructor like calling a normal method. This feature allows you to call inherited constructors without adding additional memory overhead.
Tip: A common error is to try to create an object with an object reference, not with a class reference to create an object and assign it to an object reference:
VAR
Accent: tsavingsaccount;
Begin
Account.create; // Error
Account: = tsavingsaccount.create; // correct
One of DELPHI is that you can control when calling, how to call, and whether you need to call a inherited constructor. This feature allows you to build a powerful class, but to a certain extent make the error easily.
Delphi always constructs derived classes, only when the derived class calls the inherited constructor to construct the base class. In contrast of C , it is built from the ancestors, and finally is the derived class. Thus, if there is class C inherited to B, B is inherited in A, then Delphi first constructs C, then B finally A.c first build A, then B, last C.
Method and constructor
Another big difference between C and Delphi is that in C , the constructor always runs according to the false method of the class that has been created. In Delphi, the virtual method represents all the contents of the derived class, even if the base class has not been created yet. Therefore, be careful when you write a virtual method that may be called by the constructor. Otherwise, the object may be called when the object may not be completely created. In order to prevent this, you should override the AfterConstruction method, and fill in the code that needs to wait until the object is completely created. If you want to override AfterConstruction, don't forget to call the Inherited method. A constructor can call another constructor. Delphi can distinguish whether the call comes from an object reference, so the call constructor is the same as that of the call. The most common reason to call another constructor is to place the initialization code in a single constructor. Example 2-7 shows several different ways to declare and call constructors.
Example 2-7: Declaration and Calling Constructor
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 Creger (Customer: TCUSTOMER; InterestRate: integer);
OVERLOAD;
// Note: TsaveingAccount does not need to define a destructor.
// It is simply inherited TACCOUNT constructor
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 you construct an error before setting the FCUSTOMER field, the field is NIL.
// Only the customer does not release Accounts for NIL.
IF Customer <> nil dam
Customer.releaseAccount (Self);
// Call TOBJECT.DESTROY.
Inherited destroy;
END;
Const
DefaultInterestRate = 5000; // 5%, scaled by 1000
Constructor Tsavingsaccount.create (Customer: Tcustomer);
Begin
// Call another constructor
Create (Customer, Defaultinterest);
END;
Constructor Tsavingsaccount (Customer: TCUSTOMER; InterestRate: integer);
Begin
// call taccount.create
Inherited Create (CUSTOMER);
FINTERESTRATE: = Interestrate;
END;
Destructor
The parser and constructor also hide an additional parameter. The additional parameter is set to TRUE when the first call is called. This makes the Delphi call FreeInstance to release the object. If the parser calls the inherited destructor, Delphi sets this implicit parameter to false to prevent the inheritance of the destructure from release the same object again.
Tip: A class typically has a destructor named DESTROY. Delphi allows declaration of multiple sectors - but this feature does not have any convenience. Defining multiple destructors are often easily confused and there is no practical meaning.
Before the Delphi executes the code in the destructor, it calls the virtual method BeforeDestruction. You can override this method to ensure that some transactions are processed before the designer. This feature allows you to write safe class code without having to worry about when the derived class will call the sectors of the base class.
Tip: When you define a class, you may need to overwrite the destructor method called Destroy, but do not redefine the Free method. When you release an object, you want to call the Free method instead of the destructor. This difference is very important, because free first checks whether the object reference is NIL, only the DESTROY method is called only when reference is not empty. Only for some specific occasions, it is necessary to redefine the Free method (such as a TinterFace class in the useful unit VirtIntf), as you may call Free than DESTROY.
If the constructor method and the AfterConstruction method have triggered an exception, Delphi will automatically call the destructor. When writing a destructor, you must realize that the object being revoked may not be completely created. Delphi ensures that all field initial values are empty, but if an exception is thrown in the constructor, certain fields may be initialized and some are not initialized. If the constructor directly releases the object and pointer, then ... don't have to worry about this, because the free method and the FreeMem process automatically checks if the pointer is empty. If the constructor calls other methods, it will also check if the pointer is empty.