Lecture notes, cheat sheets
Computer science and information technology. Assembler (lecture notes) Directory / Lecture notes, cheat sheets Table of contents (expand) LECTURE No. 13. Compatibility of object types 1. Encapsulation The combination of code and data in an object is called encapsulation. In principle, it is possible to provide enough methods so that the user of an object will never access the object's fields directly. Some other object-oriented languages, such as Smalltalk, require mandatory encapsulation, but Borland Pascal has a choice. For example, the TEmployee and THourly objects are written in such a way that there is absolutely no need to directly access their internal data fields: type Temployee = object Name, Title: string[25]; Rate: Real; procedure Init(AName, ATitle: string; ARate: Real); function GetName : String; function GetTitle : String; function GetRate : Real; function GetPayAmount: Real; end; THourly = object(TEmployee) Time: Integer; procedure Init(AName, ATitle: string; ARate: Real, Atime: Integer); function GetPayAmount: Real; end; There are only four data fields here: Name, Title, Rate and Time. The GetName and GetTitle methods display the worker's last name and position, respectively. The GetPayAmount method uses Rate, and in the case of a working THourly and Time to calculate the amount of payments to the working. There is no longer a need to refer directly to these data fields. Assuming the existence of an AnHourly instance of type THourly, we could use a set of methods to manipulate AnHourly data fields like this: with An hourly do begin Init (Aleksandr Petrov, Fork lift operator' 12.95, 62); {Displays the last name, position and amount of payments} show; end; It should be noted that access to the fields of an object is carried out only with the help of methods of this object. 2. Expanding Objects Unfortunately, standard Pascal does not provide any facilities for creating flexible procedures that allow you to work with completely different data types. Object-oriented programming solves this problem with inheritance: if a derived type is defined, then the methods of the parent type are inherited, but they can be overridden if desired. To override an inherited method, simply declare a new method with the same name as the inherited method, but with a different body and (if necessary) a different set of parameters. Let's define a child type of TEmployee that represents an employee who is paid an hourly rate in the following example: const PayPeriods = 26; { payment periods } Overtime Threshold = 80; { for the payment period } OvertimeFactor = 1.5; { hourly rate } type THourly = object(TEmployee) Time: Integer; procedure Init(AName, ATitle: string; ARate: Real, Atime: Integer); function GetPayAmount: Real; end; procedure THourly.Init(AName, ATitle: string; ARate: Real, Atime: Integer); begin TEmployee.Init(AName, ATitle, ARate); Time := ATime; end; function THourly.GetPayAmount: Real; var Overtime: Integer; begin Overtime := Time - OvertimeThreshold; if Overtime > 0 then GetPayAmount := RoundPay(OvertimeThreshold * Rate + Rate OverTime * OvertimeFactor * Rate) else GetPayAmount := RoundPay(Time * Rate) end; A person who is paid an hourly rate is a worker: he has everything that is used to define the TEmployee object (name, position, rate), and only the amount of money received by the hourly person depends on how many hours he worked during the period payable. Thus, THourly also requires a Time field. Because THourly defines a new Time field, its initialization requires a new Init method that initializes both the time and the inherited fields. Instead of directly assigning values to inherited fields such as Name, Title, and Rate, why not reuse the TEmployee object's initialization method (illustrated by the first THourly Init statement). Calling a method that is being overridden is not the best style. In general, it is possible that TEmployee.Init performs an important but hidden initialization. When calling an overridden method, you must be sure that the derived object type includes the parent's functionality. In addition, any change in the parent method automatically affects all child methods. After calling TEmployee.Init, THourly.Init can then perform its own initialization, which in this case only consists of assigning the value passed in ATime. Another example of an overridden method is the THourly.GetPayAmount function, which calculates the payout amount for an hourly employee. In fact, each type of TEmployee object has its own GetPayAmount method, since the type of worker depends on how the calculation is made. The THourly.GetPayAmount method should take into account how many hours the employee worked, whether there was overtime, what the increase factor for overtime was, etc. TSalaried method. GetPayAmount should only divide the employee's rate by the number of payments in each year (in our example). unit workers; interface const PayPeriods = 26; {in year} Overtime Threshold = 80; {for each payment period} OvertimeFactor=1.5; {increase against normal payment} type Temployee = object Name, Title: string[25]; Rate: Real; procedure Init(AName, ATitle: string; ARate: Real); function GetName : String; function GetTitle : String; function GetRate : Real; function GetPayAmount: Real; end; THourly = object(TEmployee) Time: Integer; procedure Init(AName, ATitle: string; ARate: Real, Atime: Integer); function GetPayAmount: Real; function GetTime: Real; end; TSalaried = object(TEmployee) function GetPayAmount: Real; end; TCommissioned = object(TSalaried) Commission: Real; Sales Amount : Real; constructor Init(AName, ATitle: String; ARate, ACommission, ASalesAmount: Real); function GetPayAmount: Real; end; implementation function RoundPay(Wages: Real) : Real; {round up payouts to ignore amounts less than monetary unit} begin RoundPay := Trunc(Wages * 100) / 100; . . . TEmployee is the top of our object hierarchy and contains the first GetPayAmount method. function TEmployee.GetPayAmount : Real; begin RunError(211); { give runtime error } end; It may come as a surprise that the method gives a run-time error. If Employee.GetPayAmount is called, an error occurs in the program. Why? Because TEmployee is the top of our object hierarchy and doesn't define a real worker; therefore, none of the TEmployee methods are called in a particular way, although they may be inherited. All of our employees are either hourly, salaried or piecework. A run-time error terminates program execution and outputs 211, which corresponds to an error message associated with an abstract method call (if the program calls TEmployee.GetPayAmount by mistake). Below is the THourly.GetPayAmount method, which takes into account things like overtime pay, hours worked, etc. function THourly.GetPayAMount : Real; var OverTime: Integer; begin Overtime := Time - OvertimeThreshold; if Overtime > 0 then GetPayAmount := RoundPay(OvertimeThreshold * Rate + Rate OverTime * OvertimeFactor * Rate) else GetPayAmount := RoundPay(Time * Rate) end; The TSalaried.GetPayAmount method is much simpler; bet in it divided by the number of payments: function TSalaried.GetPayAmount : Real; begin GetPayAmount := RoundPay(Rate / PayPeriods); end; If you look at the TCommissioned.GetPayAmount method, you'll see that it calls TSalaried.GetPayAmount, calculates the commission, and adds it to the value returned by the TSalaried method. GetPayAmount. function TCommissioned.GetPayAmount : Real; begin GetPayAmount := RoundPay(TSalaried.GetPayAmount + Commission * Sales Amount); end; Important note: While methods can be overridden, data fields cannot be overridden. Once a data field has been defined in an object hierarchy, no child type can define a data field with exactly the same name. 3. Compatibility of object types Inheritance modifies Borland Pascal's type compatibility rules to some extent. Among other things, a derived type inherits the type compatibility of all its parent types. This extended type compatibility takes three forms: 1) between implementations of objects; 2) between pointers to object implementations; 3) between formal and actual parameters. However, it is very important to remember that in all three forms, type compatibility only extends from child to parent. In other words, child types can be freely used in place of parent types, but not vice versa. For example, TSalaried is a child of TEmployee and TSosh-missioned is a child of TSalaried. With that in mind, consider the following descriptions: type PEmployee = ^TEmployee; PSalaried = ^TSalaried; PCommissioned = ^TCommissioned; var AnEmployee: TEmployee; ASalaried: TSalaried; PCommissioned: TCommissioned; TEmployeePtr: PEmployee; TSalariedPtr: PSalaried; TCommissionedPtr: PCommissioned; Under these descriptions, the following operators are valid assignments: AnEmployee :=ASalaried; ASalaried := ACommissioned; TCommissionedPtr := ACommissioned; Note A parent object can be assigned an instance of any of its derived types. Back assignments are not allowed. This concept is new to Pascal, and at first it might be hard to remember what order type compatibility comes in. You need to think like this: the source must be able to completely fill the receiver. Derived types contain everything that their parent types contain due to the property of inheritance. Therefore, the derived type is either exactly the same size, or (which is most often the case) it is larger than its parent, but never smaller. Assigning a parent (parent) object to a child (child) could leave some fields of the child object undefined, which is dangerous and therefore illegal. In assignment statements, only fields that are common to both types will be copied from the source to the destination. In the assignment operator: AnEmployee:= ACommissioned; Only the Name, Title, and Rate fields from ACommissioned will be copied to AnEmployee, since these are the only fields that are common to TCommissioned and TEmployee. Type compatibility also works between pointers to object types, and follows the same general rules as for object implementations. A pointer to a child can be assigned to a pointer to the parent. Given the previous definitions, the following pointer assignments are valid: TSalariedPtr:= TCommissionedPtr; TEmployeePtr:= TSalariedPtr; TEmployeePtr:= PCommissionedPtr; Remember that reverse assignments are not allowed! A formal parameter (either a value or a variable parameter) of a given object type can take as its actual parameter an object of its own type or objects of all child types. If you define a procedure header like this: procedure CalcFedTax(Victim: TSalaried); then the actual parameter types can be TSalaried or TCommissioned, but not TEmployee. Victim can also be a variable parameter. In this case, the same compatibility rules are followed. Comment There is a fundamental difference between value parameters and variable parameters. A value parameter is a pointer to the actual object passed as a parameter, while a variable parameter is just a copy of the actual parameter. Moreover, this copy includes only those fields that are included in the type of the formal value parameter. This means that the actual parameter is literally converted to the type of the formal parameter. A variable parameter is more like casting to a pattern, in the sense that the actual parameter remains unchanged. Similarly, if the formal parameter is a pointer to an object type, the actual parameter can be a pointer to that object type or to any child type. Let the title of the procedure be given: procedure Worker.Add(AWorker: PSalared); Valid actual parameter types would then be PSalaried or PCommissioned, but not PEmployee. Author: Tsvetkova A.V. << Back: Object Type Compatibility (Encapsulation. Extensible objects. Object type compatibility) >> Forward: Registers (Microprocessor system registers. Control registers. System address registers. Debug registers) We recommend interesting articles Section Lecture notes, cheat sheets: 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: ▪ Excitons can increase the energy efficiency of electrons ▪ Coffee can change the sense of taste ▪ Stress in dogs is associated with the emotional state of the owners ▪ New microcontroller from Maxim ▪ High-speed optical communication Li-Fi News feed of science and technology, new electronics
Interesting materials of the Free Technical Library: ▪ section of the site Instructions for use. Article selection ▪ article One goal game. Popular expression ▪ article How many aggregate states of matter are currently known? Detailed answer ▪ article Shandra comb. Legends, cultivation, methods of application
Leave your comment on this article: All languages of this page Home page | Library | Articles | Website map | Site Reviews www.diagram.com.ua |