Lecture notes, cheat sheets
Computer science and information technology. Compatibility of object types (lecture notes) Directory / Lecture notes, cheat sheets Table of contents (expand) LECTURE No. 12. Methods 1. Methods A method declaration inside an object type corresponds to a forward method declaration (forward). Thus, somewhere after an object type declaration, but within the same scope as the scope of the object type declaration, a method must be implemented by defining its declaration. For procedural and functional methods, the defining declaration takes the form of a normal procedure or function declaration, with the exception that in this case the procedure or function identifier is treated as a method identifier. For constructor and destructor methods, the defining declaration takes the form of a procedure method declaration, with the exception that the reserved word procedure is replaced by the reserved word constructor or destructor. The defining method declaration may, but need not, repeat the list of formal parameters of the method header in the object type. In this case, the method header must exactly match the header in the object type in order, types, and parameter names, and in the return type of the function result if the method is a function. The defining description of a method always contains an implicit parameter with the identifier Self, corresponding to a formal variable parameter that has an object type. Within a method block, Self represents the instance whose method component was specified to invoke the method. Thus, any changes to the values of the Self fields are reflected in the instance. The scope of an object type bean identifier extends to blocks of procedures, functions, constructors, and destructors that implement methods of that object type. The effect is the same as if a with statement of the following form were inserted at the beginning of the method block: with self do begin ... end; Based on these considerations, the spelling of component identifiers, formal method parameters, Self, and any identifier introduced into the executable part of the method must be unique. If a unique method identifier is required, then the qualified method identifier is used. It consists of an object type identifier followed by a dot and a method identifier. As with any other identifier, a qualified method identifier may optionally be preceded by a package identifier and a period. Virtual Methods Methods are static by default, but except for constructors, they can be virtual (by including the virtual directive in the method declaration). The compiler resolves references to static method calls during the compilation process, while calls to virtual methods are resolved at run time. This is sometimes called late binding. If an object type declares or inherits any virtual method, then the variables of that type must be initialized by calling a constructor before calling any virtual method. Thus, an object type that describes or inherits a virtual method must also describe or inherit at least one constructor method. An object type can override any of the methods it inherits from its parents. If a method declaration in a child specifies the same method identifier as a method declaration in the parent, then the declaration in the child overrides the declaration in the parent. The scope of an overriding method expands to the scope of the child in which the method was introduced, and will remain so until the method identifier is overridden again. Overriding a static method is independent of changing the method header. In contrast, a virtual method override must preserve the order, parameter types and names, and function result types, if any. Moreover, the redefinition must again include the virtual directive. Dynamic Methods Borland Pascal supports additional late-bound methods called dynamic methods. Dynamic methods differ from virtual methods only in the way they are dispatched at runtime. In all other respects, dynamic methods are considered equivalent to virtual methods. A dynamic method declaration is equivalent to a virtual method declaration, but the dynamic method declaration must include the dynamic method index, which is specified immediately after the virtual keyword. The index of a dynamic method must be an integer constant between 1 and 656535 and must be unique among the indexes of other dynamic methods contained in the object type or its ancestors. For example: procedure FileOpen(var Msg: TMessage); virtual 100; An override of a dynamic method must match the order, types, and names of the parameters, and exactly match the result type of the function of the parent method. The override must also include a virtual directive followed by the same dynamic method index that was specified in the ancestor object type. 2. Constructors and destructors Constructors and destructors are specialized forms of methods. Used in connection with the extended syntax of the New and Dispose standard procedures, constructors and destructors have the ability to place and remove dynamic objects. In addition, constructors have the ability to perform the required initialization of objects containing virtual methods. Like all methods, constructors and destructors can be inherited, and objects can contain any number of constructors and destructors. Constructors are used to initialize newly created objects. Typically, initialization is based on the values passed to the constructor as parameters. A constructor cannot be virtual because the dispatch mechanism of a virtual method depends on the constructor that initialized the object first. Here are some examples of constructors: constructor Field.Copy(var F: Field); begin Self := F; end; constructor Field.Init(FX, FY, FLen: integer; FName: string); begin X := FX; Y := FY; GetMem(Name, Length(FName) + 1); Name^ := FName; end; constructor TStrField.Init(FX, FY, FLen: integer; FName: string); begin inherited Init(FX, FY, FLen, FName); Field.Init(FX, FY, FLen, FName); GetMem(Value, Len); Value^ := ''; end; The main action of a constructor of a derived (child) type, such as the above TStr Field. Init is almost always a call to the appropriate constructor of its immediate parent to initialize the inherited fields of the object. After executing this procedure, the constructor initializes the fields of the object that belong only to the derived type. Destructors are the opposite of constructors and are used to clean up objects after they have been used. Normally, cleanup consists of removing all pointer fields in the object. Note A destructor can be virtual, and often is. A destructor rarely has parameters. Here are some examples of destructors: destructor Field Done; begin FreeMem(Name, Length(Name^) + 1); end; destructor StrField.Done; begin FreeMem(Value, Len); Field Done; end; The destructor of a child type, such as the TStrField above. Done, typically first removes the pointer fields introduced in the derived type, and then, as a last step, calls the appropriate collector-destructor of the immediate parent to remove the object's inherited pointer fields. 3. Destructors Borland Pascal provides a special type of method called a garbage collector (or destructor) for cleaning up and deleting a dynamically allocated object. The destructor combines the step of deleting an object with any other actions or tasks required for that type of object. You can define multiple destructors for a single object type. The destructor is defined along with all other object methods in the object's type definition: type Temployee = object Name: string[25]; Title: string[25]; Rate: Real; constructor Init(AName, ATitle: String; ARate: Real); destructor Done; virtual; function GetName: String; function GetTitle: String; function GetRate: Rate; virtual; function GetPayAmount: Real; virtual; end; Destructors can be inherited and they can be either static or virtual. Since different finalizers tend to require different types of objects, it is generally recommended that destructors are always virtual so that the correct destructor is executed for each type of object. The reserved word destructor does not need to be specified for every cleanup method, even if the object's type definition contains virtual methods. Destructors really only work on dynamically allocated objects. When a dynamically allocated object is cleaned up, the destructor performs a special function: it ensures that the correct number of bytes are always freed in the dynamically allocated memory area. There can be no concern about using a destructor with statically allocated objects; in fact, by not passing the object's type to the destructor, the programmer deprives an object of that type of the full benefits of dynamic memory management in Borland Pascal. Destructors actually become themselves when polymorphic objects must be cleared and when the memory they occupy must be deallocated. Polymorphic objects are those objects that have been assigned to a parent type due to Borland Pascal's extended type compatibility rules. An instance of an object of type THourly assigned to a variable of type TEmployee is an example of a polymorphic object. These rules can also be applied to objects; a pointer to THourly can freely be assigned to a pointer to TEmployee, and the object pointed to by that pointer will again be a polymorphic object. The term "polymorphic" is appropriate because code that processes an object "doesn't know" exactly at compile time what type of object it will eventually need to process. The only thing it knows is that this object belongs to a hierarchy of objects that are descendants of the specified object type. Obviously, the sizes of the object types are different. So when it comes time to clean up a heap-allocated polymorphic object, how does Dispose know how many bytes of heap space to free? At compile time, no information about the object's size can be extracted from a polymorphic object. The destructor solves this puzzle by referring to the place where this information is written - in the TCM implementation variables. Each TBM of an object type contains the size in bytes of that object type. The table of virtual methods of any object is available through the hidden parameter Self, sent to the method when the method is called. A destructor is just a type of method, and so when an object calls it, the destructor gets a copy of Self on the stack. Thus, if an object is polymorphic at compile time, it will never be polymorphic at run time due to late binding. To perform this late-bound deallocation, the destructor must be called as part of the extended syntax of the Dispose procedure: Dispose(P, Done); (A call to the destructor outside of the Dispose procedure does not deallocate any memory at all.) What is really happening here is that the garbage collector of the object pointed to by P is executed as a normal method. However, once the last action is complete, the destructor looks up the size of its type's implementation in the TCM and passes the size on to the Dispose procedure. The Dispose procedure terminates the process by deleting the correct number of bytes of the heap space that (the space) previously belonged to P^. The number of bytes to be freed will be correct regardless of whether P pointed to an instance of type TSalaried, or whether it pointed to one of the child types of type TSalaried, such as TCommissioned. Note that the destructor method itself can be empty and perform only this function: destructorAnObject.Done; begin end; What is useful in this destructor is not the property of its body, however, the compiler generates epilogue code in response to the destructor reserved word. It's like a module that doesn't export anything, but does some invisible work by executing its initialization section before starting the program. All action takes place behind the scenes. 4. Virtual Methods A method becomes virtual if its object type declaration is followed by the new reserved word virtual. If a method in a parent type is declared as virtual, then all methods with the same name in child types must also be declared virtual to avoid a compiler error. The following are the objects from the example payroll, properly virtualized: type PEmployee = ^TEmployee; Temployee = object Name, Title: string[25]; Rate: Real; constructor Init(AName, ATitle: String; ARate: Real); function GetPayAmount: Real; virtual; function GetName : String; function GetTitle : String; function GetRate : Real; procedure Show; virtual; end; PHourly = ^THourly; THourly = object(TEmployee); Time: Integer; constructor Init(AName, ATitle: String; ARate: Real; Time: Integer); function GetPayAmount: Real; virtual; function GetTime: Integer; end; PSalaried = ^TSalaried; TSalaried = object(TEmployee); function GetPayAmount: Real; virtual; end; PCommissioned = ^TCommissioned; TCommissioned = object(Salaried); Commission: Real; Sales Amount : Real; constructor Init(AName, ATitle: String; ARate, ACommission, ASalesAmount: Real); function GetPayAmount: Real; virtual; end; A constructor is a special type of procedure that does some setup work for the virtual method mechanism. Moreover, the constructor must be called before any virtual method is called. Calling a virtual method without first calling the constructor can block the system, and the compiler has no way to check the order in which the methods are called. Every object type that has virtual methods must have a constructor. A warning The constructor must be called before any other virtual method is called. Calling a virtual method without a previous call to the constructor can cause a system lock and the compiler cannot check the order in which the methods are called. Note For object constructors, it is suggested to use the identifier Init. Each distinct object instance must be initialized with a separate constructor call. It is not enough to initialize one instance of an object and then assign that instance to others. Other instances, even if they may contain valid data, will not be initialized with an assignment operator and will block the system on any calls to their virtual methods. For example: var FBee, GBee: Bee; { create two Bee instances } begin FBee.Init(5, 9) { constructor call for FBee } GBee := FBee; { Gbee is invalid! } end; What exactly does a constructor create? Each object type contains something called a virtual method table (VMT) in the data segment. The TVM contains the size of the object type and, for each virtual method, a pointer to the code that executes that method. A constructor establishes a relationship between the object's calling implementation and the object's type TCM. It is important to remember that there is only one TBM for each object type. Separate instances of an object type (i.e., variables of this type) contain only the connection to the TBM, but not the TBM itself. The constructor sets the value of this connection to TBM. It is because of this that nowhere can you start execution before calling the constructor. 5. Object data fields and formal method parameters The implication of the fact that methods and their objects share a common scope is that a method's formal parameters cannot be identical to any of the object's data fields. This is not some new limitation imposed by object-oriented programming, but rather the same old scope rules that Pascal has always had. This is the same as preventing a procedure's formal parameters from being identical to the procedure's local variables: procedure CrunchIt(Crunchee: MyDataRec, Crunchby, ErrorCode: integer); var A, B: char; ErrorCode: integer; begin . . . A procedure's local variables and its formal parameters share a common scope and therefore cannot be identical. You will get "Error 4: Duplicate identifier" if you try to compile something like this, the same error occurs when you try to set a formal method parameter to the name of the field of the object to which the method belongs. The circumstances are somewhat different, as putting the procedure header inside a data structure is a nod to an innovation in Turbo Pascal, but the basic principles of Pascal scope have not changed. Author: Tsvetkova A.V. << Back: Methods (Methods. Constructors and destructors. Destructors. Virtual methods. Object data fields and formal method parameters) >> Forward: Assembler (About assembler. Microprocessor software model. User registers. General purpose registers. Segment registers. Status and control registers) We recommend interesting articles Section Lecture notes, cheat sheets: ▪ Methods of teaching psychology. Lecture notes ▪ pathological physiology. Crib ▪ History of culture. Lecture notes See other articles Section Lecture notes, cheat sheets. Read and write useful comments on this article. Latest news of science and technology, new electronics: The existence of an entropy rule for quantum entanglement has been proven
09.05.2024 Mini air conditioner Sony Reon Pocket 5
09.05.2024 Energy from space for Starship
08.05.2024
Other interesting news: ▪ SIMO PMIC Converter MAX77654 ▪ Photonic chip converting waves with high efficiency ▪ Film that increases the impact resistance of the smartphone display ▪ Aquarium fish for astronauts News feed of science and technology, new electronics
Interesting materials of the Free Technical Library: ▪ site section Power regulators, thermometers, heat stabilizers. Article selection ▪ article Flea market. Popular expression ▪ article Lake Ladoga. Nature miracle ▪ article Television antennas. Directory ▪ article S-metr for HF radio. Encyclopedia of radio electronics and electrical engineering
Leave your comment on this article: All languages of this page Home page | Library | Articles | Website map | Site Reviews www.diagram.com.ua |