Delphi Object Model (Part II)

zhaozj2021-02-11  153

Delphi Object Model (Part II)

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 .)

Object)

Object is a dynamic example of a class. This dynamic instance contains all fields of this class and its ancestors. The object also contains an implicit field to save a class reference to the class belonging to the object.

Objects always assign from the heap to memory, so object references actually point to a pointer to this object. Program designers have the responsibility of creating and releaseing objects at a suitable time. In order to create an object, we use class references and call constructor methods, as shown in the following example:

Obj: = tsomeclass.create;

Most constructors are named CREATE, but this is just a convention, not Delphi's request. Sometimes you will find other names constructor, especially some of the old classes defined before Delphi not supporting the method of overloading. To maximize compatibility with C Builder (because C Builder does not allow custom constructor names), it is best to use Create, the original constructor method. To delete an object that is no longer used in the program, call the Free method. In order to ensure that the object can be properly released even if there is an abnormality trigger, use the try-finally exception handling. As shown in the following example:

Obj: = tsomehaclass.create;

Try

Obj.dosomethingthatmightraiseanenexception;

Obj.dosomethingelse;

Finally

Obj.free;

END;

When a global variable is released, if the variable is always set to NIL after the object is released, the variable containing the invalid pointer will not be left. Be careful before the object is released to NIL before the object is released. If a method called in the constructor or constructor has a reference to the variable, you'd better set the variable to NIL to prevent possible hidden dangers. A simple method is to call the FreeAndnill process (declared in sysutils).

Globalvar: = tfruitwigglies.create;

Try

GlobalVar.EATEMUP;

Finally

Freeandnil (GlobalVar);

END;

Each object contains a separate copy of all its fields. Fields cannot be shared by multiple objects. If you really need to share a field variable, this variable is defined at the cell level or use an indirect method: use a pointer or object reference to access public data in an object.

Inheritance

A class can inherit from another class. The newly derived class inherits all fields, methods, and properties in the base class. Delphi only supports single inheritance, so the derived class has only one base class. The base class can also have its own base class, so that the cycle is constantly, a class inherits the fields, properties, and methods of all ancestors. The class can also achieve any more interface. Similar to Java, but C is different, all Delphi classes inherit the same root class, that is, TOBJECT. If the base class is not explicitly specified, Delphi automatically uses TOBJECT as the base class of the class.

Tip: The most direct parent class class is called the base class, which can be embodied in the statement of the class. The ancestors of the class can be a base class of the class or may be the other ancestors in the inheritance chain of TOBJECT. Thus, in Example 2-1, the class TcertificateOfDeposit only has a base class called Tsavingsaccount; and its ancestors are Tobject, Taccount, and Tsavingsaccount. The TOBJECT class declares some methods and a special, hidden field specifically to store references to the class belonging to the object. This hidden field points to the virtual method table (VMT) of the class. Each class has a unique VMT and all such objects share the VMT of this class.

An object reference can be assigned to an identical object type, or a variable of any ancestral class of the class. In other words, the object reference is not necessarily the same as the actual object type, which is assigned to the actual object type, which is not allowed to assign a value of the object class to the derived class, because the object may It is different types.

Delphi retains the powerful type of calibration of Pascal, so the compiler checks it according to the type of object reference declaration. In this way, all methods required must be part of the class declaration, and the compiler also conducts a routine check for the variables of the function and process. The compiler does not all bind a method of call to a specific implementation. Because if it is a virtual method, only when the runtime can be determined according to the true type of the object, which method is called. This problem is described in detail in the "Method" section of this chapter.

Use the IS operator to test the true class belonging to the object. Returns TRUE when this reference is the same or such reference is a ancestry class of the object class. Returns false when the object references is NIL or not such a class.

IF account is tcheckingaccount the ... // tests the class of account if account is tobject the ... // True When Account is not nil

You can use type conversion to get another type of object reference. Type conversion does not change objects; it just gives you a new object reference. You can usually use the AS operator for type conversion. The AS operator automatically checks the object type and will trigger a running period error when the object's class is not a subclass of the target class. (The runtime error is mapped to the EINVALIDCAST unusual.) In the SYSUTILS unit.)

Another way to convert object references is to use the name of the target class, similar function calls. This conversion does not perform type check, so it is only when you are confident. As shown in Example 2-3:

Example 2-3: Conversion of static types

VAR

Account: taccount;

CHECKING: TCHECKINGACCOUNT;

Begin

Account: = Checking; // Allow

Checking: = Account; // Compiling errors

Checking: = Account as tcheckingaccount; // No problem

Account as tform; / / trigger a running period error

Checking: = tcheckingaccount (account); // available, but not recommended

IF account is tcheckingaccount dam // better

Checking: = tcheckingaccount (account)

Else

Checking: = NIL;

Field (Field)

The field is the variable inside the object. A class can declare any of the fields, and each object has its own class and a copy of all the fields of all ancestors. Or, the field can be referred to as a data member, an instantiated variable, or a feature. Delphi does not provide class variables, class instance variables, static data members or equivalents (ie, variables shared in all objects of the same class). But you can use variables at the unit level to achieve a similar effect. Fields can be any type unless it is published. The fields in the published declaration section must have runtime type information. See Chapter III for details.

In Delphi, when you create an object, all the fields of the object are blank, that is, all pointers are initialized to nil, string, and dynamic arrays, the content is empty, the number value is 0, the value of the Boolean type For false, and the value of variable type Variant is assigned to unassigned.

The derived class can define the fields that are the same name in the ancestral class. This field of the derived class hides the field of the same name in the ancestral class. The method in the derived class is referenced by the field in the derived class, and the ancestral method is referenced by the field in the ancestral class.

Method

The method is a function or process implemented in the class. C Chinese method is called "member functions". The difference between the method and the ordinary process and function is that there is an implicit parameter in the method called Self to point to the object itself that calls the method. The SELF here is similar to C and Java. Calling a method similar to calling a normal function or process, but you have to follow the name of the method after reference, such as:

Object.method (argument);

Class Method Based on the class and its ancestors. In the class method, SELF is a reference to the class rather than reference to the object. C mid-class method is called a "static member function".

You can call the object methods declared in the class and the ancestral class. If the ancestral class and derived class define the same name, Delphi will call the method of the outermost derived. As shown in Example 2-4:

Example 2-4: Binding static method

Type

Taccount = Class

public

Procedure withdraw (Amount: Currency);

END;

Tsavingsaccount = Class (Taccount)

public

Procedure withdraw (Amount: Currency);

END;

VAR

Savings: tsavingsaccount;

Account: taccount;

Begin

...

Savings.withdraw (1000.00); // Call Tsavingsaccount.withdraw

Account.withdraw (1000.00); // call taccount.withdraw

The reason for the normal method is called a static method is that the compiler is directly bound by the implementation of the call and method. In other words, the static method is static binding. In C , a common method is called a "normal member function", called "Final Method" in Java. Most Delphi programmers do not want to use static methods, and simplify the method or non-virtual method.

The virtual method is a class of methods that are bound during operation during operation during compilation. During compilation, Delphi determines the method that can be called based on the type of object reference. Different from the implementation of a specific method directly to compile, the compiler stores an indirect pair of methods based on the actual type of object. During operation, the program finds the method in the class's runtime table (especially VMT), and then calls the method of the actual type. The true class of the object must be a class declared in the compile period, or a derived class - this is not a problem, because the VMT provides a pointer to the correct method. To declare a virtual method, you can use the Vritual indicator in the base class, and then use the Override indicator to provide new definitions of the method in the derived class. Different from Java, Delphi is still static in the default, so you must use the Virtual indicator to declare a virtual method. Unlike C , Delphi to override a false method in the derived class. You must use the Override indicator.

Example 2-5 uses the virtual method.

Example 2-5 Binding virtual method

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); // Call Tsavingsaccount.withdraw

Account: = savings;

Account.withdraw (1000.00); // Call Tsavingsaccount.withdraw

In addition to the Vritual indicator, you can also use the Dynamic indicator. The two semantics are the same, but achieved different. Finding a virtual method in VMT is fast because the compiler has built an index in VMT. Find a dynamic method slower. Calling a dynamic method is definitely in a dynamic method table (DMT). Linear lookup. Find out in the ancestors until you encounter TOBJECT or this method is found. In some occasions, dynamic methods take up less memory than virtual methods. Unless you have to write a VCL alternative, you should use the virtual method instead of a dynamic method. See Chapter 3 to learn more about content.

The virtual method and dynamic method can use the Abstract Indicator when declaring, so that this class does not have to give the definition of the method, but must override (override) in the derived class. The term "pure virtual method" is called "pure virtual method" in C . When you call a constructor containing an abstract method, Delphi will give a compilation warning and prompt you may have an error. Maybe you want to create an instance of the override and derived class of the abstract method. Classs defining a plurality of abstract methods are often referred to as an abstract class, although some people identify those classes that use only the abstract methods only define.

Tip: When you build an abstract class inherited from other abstract classes, you should use the Override and Abstract indicators to re-declare all abstraction methods. Delphi did not do this, because it is just a practice. These statements will clearly tell the code maintenance personnel what is abstract. Otherwise, the maintenance personnel may be implemented for those methods, and those methods need to remain abstract. E.g:

Type

TBaseAbStract = Class

.

END;

TderiVedabstract = Class (TBaseAbsract) Procedure method; Override; Abstract

END;

Tconcrete = Class (TderiVedabstract)

Procedure method; Override;

END;

Class methods or constructors can also be virtual. In Delphi, class reference is a real entity, you can assign it to a variable, as parameter passes, or use as a reference to call the class method. If the constructor is virtual, the class reference has a static base class type, but you can assign a derived class reference to it. Delphi will find a virtual constructor in the VMT of the class, and then call the derived class constructor. ,

Methods (and other functions and processes) can be overloaded, that is, multiple routines can have the same name, but the parameter definition must vary. Disclaimer The overload method uses the OverLoad indicator. A method inherited in the base class can be overloaded in the derived class. In this case, only derived classes need to use OverLoad indicators. After all, the authors of the base class cannot foresee other programmers to overload a inheritance method. If there is no OverLoad indicator in the derived class, the same name in the base class is shielded. As shown in Example 2-6.

Example 2-6: Overload of the method

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 blocked.

Savings.Audit; // is correct because Audiot is overloaded.

Savings.Audit (aunasty); / / correct

Checking.Audit (auinternal); // correct parti partiii

转载请注明原文地址:https://www.9cbs.com/read-5318.html

New Post(0)