home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / turbopas / totdoc11.zip / CHAPT16.TXT < prev    next >
Text File  |  1991-02-11  |  17KB  |  367 lines

  1.                                                                              OOP
  2.                                                                       Principles
  3.  
  4.  
  5.  
  6.          "The human mind treats a new idea the way the body treats a strange
  7.          protein; it rejects it."
  8.  
  9.                                                         P. B. Medawar, Biologist
  10.  
  11.  
  12.          Part 2 of the User's manual explains how, by using object oriented
  13.          programming, you can customize the Toolkit to meet your very specific
  14.          needs. In this chapter, some of the main features of OOP extensibility
  15.          are explained. If you are an experienced OOPer, you may want to skip
  16.          this chapter and proceed with the Toolkit specific text.
  17.  
  18.          If you are new to OOP, be sure to read the Object Primer starting on
  19.          page 3.1 before you look at this chapter.
  20.  
  21.  
  22. Understanding Inheritance
  23.          One of the most powerful and alluring aspects of object oriented pro-
  24.          gramming is the ability to modify and expand an object without changing
  25.          any of the object's source code. What's more, it's easy to do! The
  26.          basic approach is to create an object which inherits all the properties
  27.          of another object, i.e. you clone the object (sorry Compaq). You can
  28.          then change some of the properties of the cloned object so that it
  29.          functions the way you want it to.
  30.  
  31.          This feature allows you to enhance and improve the Toolkit without
  32.          changing a single line of Toolkit source code. That way, when we
  33.          release a new and improved version, you don't have to wrestle with two
  34.          sets of source code - the code that you changed and the code that we
  35.          changed. All you need to do is "plug in" the new Toolkit and your
  36.          objects will automatically inherit the new features added to the Tool-
  37.          kit.
  38.          To illustrate object inheritance, let's solve a practical problem.
  39.          Imagine that you use the EquipOBJ object, but need to enhance it so
  40.          that it will report if a CD-ROM is installed. Rather than change the
  41.          EquipOBJ object, the approach is to create a new object which inherits
  42.          all the properties of EquipOBJ, and add the new CD-ROM method to it.
  43.  
  44.          You may recall from chapter 3: Toolkit Basics that declaring an object
  45.          is very similar to declaring a record. To declare a object that inher-
  46.          its the properties of another object, you specify the name of the par-
  47.          ent object in parentheses after the object keyword. The following code
  48.          fragment declares a new object type, NewEquipOBJ, which inherits all
  49.          the properties of EquipOBJ:
  50.          NewEquipOBJ = object (EquipOBJ)
  51.          end; {NewEquipOBJ}
  52.  
  53. 16-2                                                       Extending the Toolkit
  54. --------------------------------------------------------------------------------
  55.  
  56.          If you create an object which is a descendant of a Toolkit object, you
  57.          must define two special methods known as the CONSTRUCTOR and the
  58.          DESTRUCTOR. Furthermore, these should be named INIT and DONE, respec-
  59.          tively. These special methods instruct Turbo Pascal to use special
  60.          memory techniques when creating and disposing of the object. The
  61.          NewEquipOBJ object declaration must be expanded to include the con-
  62.          structor and destructor methods as follows:
  63.  
  64.          NewEquipOBJ = object (EquipOBJ)
  65.             constructor Init;
  66.             destructor  Done;
  67.          end; {NewEquipOBJ}
  68.          Now we can add the new CD-ROM method to the object declaration.  Assum-
  69.          ing that the new method is just a boolean function, it would be
  70.          declared as follows:
  71.  
  72.          NewEquipOBJ = object (EquipOBJ)
  73.             constructor Init;
  74.             function    CDROM: boolean;
  75.             destructor  Done;
  76.          end; {NewEquipOBJ}
  77.          As well as adding new methods to the object, you can override or change
  78.          existing methods. For example, the GameAdapter function inherited from
  79.          EquipOBJ can be replaced with a new method by expanding the object
  80.          declaration as follows:
  81.  
  82.          NewEquipOBJ = object (EquipOBJ)
  83.             constructor Init;
  84.             function    CDROM: boolean;
  85.             function    GameAdapter: boolean;
  86.             destructor  Done;
  87.          end; {NewEquipOBJ}
  88.          Although you have only declared NewEquipOBJ with four methods, it
  89.          actually includes all the data and methods it has inherited from Equi-
  90.          pOBJ. The following table compares the data and methods declared in
  91.          EquipOBJ, with the data and methods in NewEquipOBJ. The non-bold items
  92.          are inherited.
  93.  
  94.  
  95.                        EquipOBJ                          NewEquipOBJ
  96.           vMainInfo: integer;                vMainInfo: integer;
  97.           vComputerID: byte;                 vComputerID: byte;
  98.           vRomDate: string[8];               vRomDate: string[8];
  99.           constructor Init;                  constructor Init;
  100.           function    ComputerID:byte;       function    ComputerID:byte;
  101.           function    ParallelPorts:byte;    function    ParallelPorts:byte;
  102.           function    SerialPorts:byte;      function    SerialPorts:byte;
  103.           function    FloppyDrives:byte;     function    FloppyDrives:byte;
  104.  
  105.  
  106.  
  107.  
  108. OOP Principles                                                              16-3
  109. --------------------------------------------------------------------------------
  110.  
  111.           function    ROMDate:string;        function    ROMDate:string;
  112.           function    SerialPrinter:boolean; function    SerialPrinter:boolean;
  113.           function    MathChip:boolean;      function    MathChip:boolean;
  114.           function    GameAdapter:boolean;   function    GameAdapter:boolean;
  115.           destructor  Done;                  function    CDROM:boolean;
  116.                                              destructor  Done;
  117.  
  118.  
  119.  
  120.  
  121.            Note: an inherited object may also include data items, provided
  122.            the identifiers (or variable names) are different from the ones
  123.            inherited from the parent object.
  124.  
  125.  
  126.  
  127.          The object declaration defines a new object type and should be located
  128.          in the TYPE declaration section of your program or unit. The corre-
  129.          sponding detail of each object method must be listed either in the body
  130.          of your program, or in the implementation section of a unit.
  131.  
  132.          Listed below is a unit, EXTDEM1.PAS, which fully defines the new object
  133.          NewEquipOBJ. One of the important points to note is that the construc-
  134.          tor and destructor methods must call the associated constructor and
  135.          destructor from the parent method. This ensures that the inherited data
  136.          is initialized and disposed of properly. These important statements are
  137.          highlighted in bold in the listing.
  138.  
  139.  
  140.          Unit ExtDem1;
  141.          INTERFACE
  142.  
  143.          Uses DOS,CRT, totSYS;
  144.          TYPE
  145.  
  146.          NewEquipOBJ = object (EquipOBJ)
  147.             constructor Init;
  148.             function    CDROM: boolean;
  149.             function    GameAdapter: boolean;
  150.             destructor  Done;
  151.          end; {NewEquipOBJ}
  152.          IMPLEMENTATION
  153.  
  154.          constructor NewEquipOBJ.Init;
  155.          {}
  156.          begin
  157.             EquipOBJ.Init;
  158.          end; {NewEquipOBJ.Init}
  159.  
  160.  
  161. 16-4                                                       Extending the Toolkit
  162. --------------------------------------------------------------------------------
  163.  
  164.          function NewEquipOBJ.CDROM:boolean;
  165.          {If you know how to do this - please tell us!
  166.           For now, we'll assume one isn't installed}
  167.          begin
  168.             CDROM := false;
  169.          end; {NewEquipOBJ.CDROM}
  170.  
  171.          function NewEquipOBJ.GameAdapter:boolean;
  172.          {}
  173.          begin
  174.             GameAdapter := paramstr(1) = '/G';
  175.          end; {NewEquipOBJ.GameAdapter}
  176.          destructor NewEquipOBJ.Done;
  177.          {}
  178.          begin
  179.             EquipOBJ.Done;
  180.          end; {NewEquipOBJ.Done}
  181.  
  182.          end.
  183.  
  184.          The body of the CD-ROM and GameAdapter methods would normally contain
  185.          your custom code. In this case, their value is limited. But you get the
  186.          idea!
  187.  
  188.          Take a look at the object hierarchy diagrams at the beginning of the
  189.          Flash Cards. They show the Toolkit's parent-sibling object relation-
  190.          ships. For example, ScrollWinOBJ inherits MoveWinOBJ, which, in turn,
  191.          inherits WinOBJ.
  192.  
  193.  
  194. Mastering Extensibility
  195.  
  196.          All the methods in the EquipOBJ object, discussed in the last section,
  197.          are known as static methods. Static methods are usually independent
  198.          methods, i.e. methods which do not call other methods in the object.
  199.          For example, the GameAdapter method has no relationship with the Math-
  200.          Chip method or any other EquipOBJ method.
  201.          Inheritance becomes somewhat more complicated when methods call other
  202.          methods from the same object. The problem is best illustrated by exam-
  203.          ple. The unit listing below contains an object, PrintOBJ, which is used
  204.          to print strings or integers to the printer connected to LPT1. The
  205.          objective is to create a descendant object which can print to any
  206.          printer port.
  207.  
  208.          Unit BadPrint;
  209.          INTERFACE
  210.  
  211.          Uses DOS,CRT, totSTR;
  212.  
  213.  
  214.  
  215. OOP Principles                                                              16-5
  216. --------------------------------------------------------------------------------
  217.  
  218.          TYPE
  219.          PrintOBJ = object
  220.             constructor Init;
  221.             procedure   PrintChar(Ch:char);
  222.             procedure   PrintStr(Str:string);
  223.             procedure   PrintInt(Int:integer);
  224.             destructor  Done;
  225.          end; {PrintOBJ}
  226.  
  227.          IMPLEMENTATION
  228.          constructor PrintOBJ.Init;
  229.          {no data to initialize}
  230.          begin
  231.          end; {PrintOBJ.Init}
  232.  
  233.          procedure PrintOBJ.PrintChar(Ch:char);
  234.          {}
  235.          var
  236.            Lst: text;
  237.          begin
  238.             Assign(Lst,'LPT1');
  239.             Rewrite(Lst);
  240.             Write(Lst,Ch);
  241.             Close(Lst);
  242.          end; {PrintOBJ.PrintChar}
  243.          procedure PrintOBJ.PrintStr(Str:string);
  244.          {}
  245.          var I : integer;
  246.          begin
  247.             for I := 1 to length(Str) do
  248.                 PrintChar(Str[I]);
  249.          end; {PrintOBJ.PrintStr}
  250.  
  251.          procedure PrintOBJ.PrintInt(Int:integer);
  252.          {}
  253.          var I:integer; Str:string;
  254.          begin
  255.             Str := IntToStr(Int);
  256.             for I := 1 to length(Str) do
  257.                 PrintChar(Str[I]);
  258.          end; {PrintOBJ.PrintInt}
  259.          destructor PrintOBJ.Done;
  260.          {no data to dispose of}
  261.          begin
  262.          end; {PrintOBJ.Done}
  263.  
  264.          end.
  265.  
  266.  
  267.  
  268. 16-6                                                       Extending the Toolkit
  269. --------------------------------------------------------------------------------
  270.  
  271.          The two main methods are PrintStr and PrintInt, but these methods both
  272.          call the method PrintChar to print each individual character. (By
  273.          design, the code is simplistic; just remember the main purpose is to
  274.          teach you about extensibility, not how to write to the printer!)
  275.  
  276.          PrintChar is the root of the problem because it is hard-coded to print
  277.          to LPT1. If you are getting into the OOP groove, and you're from Cali-
  278.          fornia, you might say: "No sweat, DUDE! Create a descendant object and
  279.          replace the PrintChar method. Gnarly!" It's the right idea, but in this
  280.          case it won't work.
  281.          If you create a descendant object, NewPrintOBJ, and replace the Print-
  282.          Char method, the object will inherit the PrintStr and PrintInt methods.
  283.          However, when you call PrintStr or PrintInt, they will in turn call
  284.          THEIR object's version of PrintChar, i.e. PrintOBJ.PrintChar not New-
  285.          PrintOBJ.PrintChar. One solution is to also replace the PrintStr and
  286.          PrintInt methods, but then you have rewritten the entire object without
  287.          taking advantage of inheritance!
  288.  
  289.          The OOP solution lies in virtual methods. If the PrintChar method in
  290.          PrintOBJ is declared as virtual, Turbo Pascal will manage the situation
  291.          very differently. A method is identified as virtual by adding the key-
  292.          word virtual at the end of the method declaration. The following code
  293.          fragment shows the PrintOBJ object declared with a virtual method:
  294.          PrintOBJ = object
  295.             constructor Init;
  296.             procedure   PrintChar(Ch:char); virtual;
  297.             procedure   PrintStr(Str:string);
  298.             procedure   PrintInt(Int:integer);
  299.             destructor  Done;
  300.          end; {PrintOBJ}
  301.  
  302.          The virtual keyword instructs Turbo Pascal to late bind the PrintChar
  303.          method. That is, the compiler implements a special linking method which
  304.          ensures that descendant objects, like NewPrintOBJ, can redefine any
  305.          virtual methods. The redefined version of the method will always be
  306.          called even by inherited methods. For example, the following code
  307.          defines a descendant of PrintOBJ (assuming PrintOBJ used the virtual
  308.          keyword):
  309.          NewPrintOBJ = object (PrintOBJ)
  310.             constructor Init;
  311.             procedure   PrintChar(Ch:char); virtual;
  312.             destructor  Done;
  313.          end; {NewPrintOBJ}
  314.  
  315.          Now if the inherited method NewPrintOBJ.PrintStr is called, Turbo Pas-
  316.          cal is smart enough to ensure that PrintStr calls NewPrintOBJ.Print-
  317.          Char, and not PrintOBJ.PrintChar. All you would have to do is customize
  318.          PrintChar to print to any port and the problem is solved. The on-disk
  319.          demo file, EXTDEM2.PAS, includes the full solution for this example.
  320.  
  321.  
  322. OOP Principles                                                              16-7
  323. --------------------------------------------------------------------------------
  324.  
  325.            Note: if an object includes virtual methods, the object must have
  326.            a constructor and destructor. In addition, if a method is declared
  327.            as virtual, all descendant methods with the same name must also be
  328.            declared virtual, and they must have identical passed parameters.
  329.  
  330.  
  331.  
  332.          The down side of virtual methods is that they will always be linked
  333.          into your EXE program code whether the methods are called or not. If
  334.          this were not so, there would be good justification for making every
  335.          method virtual. As it is, the Toolkit only makes methods virtual if
  336.          they are likely to be accessed in some descendant object. It's a trade-
  337.          off between complete flexibility and program code size.
  338.  
  339.          You may have heard or read about polymorphism. Polymorphism allows sim-
  340.          ilar objects to execute different code when the same call is made to
  341.          them from some independent routine. It is virtual methods which provide
  342.          Turbo Pascal objects with polymorphism. One of the best Toolkit exam-
  343.          ples of polymorphism is in the totIO units. The FormOBJ object, which
  344.          controls all the input fields, knows that every input field object has
  345.          the methods Display, Select, ProcessKey and Suspend. Any object which
  346.          is created as a descendant from BaseIOOBJ will inherit these methods,
  347.          and can be managed by FormOBJ. All FormOBJ needs to do is call one of
  348.          these methods. (Actually, there are a few more methods than listed, but
  349.          the theory still holds.) In chapter 20: Extending Input Fields the full
  350.          power of polymorphism is explored.
  351.  
  352.  
  353. Know Your Ancestor!
  354.  
  355.          As you have probably assessed, you need to know some details about the
  356.          Toolkit objects before you can start to extend them. You need to know
  357.          about the methods and the data that will be inherited. Its a good idea
  358.          to print the interface section of each unit, as this provides all the
  359.          important information about each object's data and methods.
  360.          This concludes the brief explanation of OOP. Remember that the text is
  361.          aimed at helping you to extend the Toolkit. You should consider re-
  362.          reading the discussion of object-oriented programming in the Turbo Pas-
  363.          cal's User's Guide. It might make a lot more sense now! In addition, it
  364.          covers, in much greater depth, some of the principles introduced in
  365.          this chapter.
  366.  
  367.