home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / comp / lang / cplus / 18367 < prev    next >
Encoding:
Text File  |  1992-12-23  |  3.9 KB  |  117 lines

  1. Newsgroups: comp.lang.c++
  2. Path: sparky!uunet!microsoft!wingnut!pauljo
  3. From: pauljo@microsoft.com (Paul Johns)
  4. Subject: Re: Any inheritance experts out there? reprise
  5. Message-ID: <1992Dec23.200342.29146@microsoft.com>
  6. Date: 23 Dec 92 20:03:42 GMT
  7. Organization: Microsoft:  Redmond, Washington, USA
  8. Keywords: inheritance, virtual
  9. References: <4021@hpwala.wal.hp.com> 
  10. Lines: 105
  11.  
  12. I think you DON'T want to use a template here for the class.
  13.  
  14. Instead, an abstract base class "GENERIC_DEVICE" would contain
  15. the pure virtual function declarations for the interface to the
  16. class.
  17.  
  18. Each device would directly or indirectly derive from GENERIC_DEVICE 
  19. and would provide definitions for all of the functions.
  20.  
  21. Similar devices (block vs. character) would have an additional
  22. abstract base class put in.  And so forth.
  23.  
  24. So your inheritance hierarchy might look something like this:
  25.  
  26.     GENERIC_DEVICE <--- BLOCK_DEVICE <--- DISK_DRIVE <--- specific controller
  27.         ^-----------CHAR_DEVICE  <--- PRINTER    <--- specific printer
  28.  
  29. (You can tell from this derivation that I have MS-DOS background, can't
  30. you?)
  31.  
  32. Note that the only non-abstract classes are the specific controller and
  33. specific printer classes.  All the other classes have at least one pure
  34. virtual function.  Therefore, the only objects that can be created are of 
  35. the specific classes.
  36.  
  37. (BTW, if you have areas of commonality that span branches of the hierarchy, 
  38. you may want to put that functionality in a class and use multiple 
  39. inheritance.)
  40.  
  41. Your user would declare a pointer to the appropriate class and use it as
  42. appropriate for that class.
  43.  
  44. For instance, if they were going to only do operations that were supported
  45. on all devices, they'd declare "GENERIC_DEVICE *p;"  If they were doing
  46. disk operations, they'd declare a pointer to a DISK_DRIVE.
  47.  
  48. They will only need the headers for the pointers they use.  They will
  49. never need pointers to specific devices.  (One hopes....)
  50.  
  51. You'll need to provide a set of overloaded functions that will allocate 
  52. an object for them and a way to select among the overloads.  For instance:
  53.  
  54.     enum DISK_DRIVE_ID { D_DISK_TYPE_1, ... };    // goes in USER.H
  55.  
  56.     DISK_DRIVE * MakeObject(DISK_DRIVE_ID d)  {
  57.         switch (d)  {
  58.             case D_DISK_TYPE_1:  return new DISK_TYPE_1;
  59.             // ...
  60.         }
  61.     }
  62.  
  63.     enum PRINTER_ID { D_PRINTER_TYPE_1, ... };    // goes in USER.H
  64.  
  65.     PRINTER * MakeObject(PRINTER_ID d)  {
  66.         switch (d)  {
  67.             case D_PRINTER_TYPE_1:  return new PRINTER_TYPE_1;
  68.         }
  69.     };
  70.  
  71. I'm assuming that your specific device classes are called DISK_TYPE_1 and
  72. PRINTER_TYPE_1.
  73.  
  74. You would only have enum/MakeObject pairs for the abstract base classes
  75. which are immediate bases of actual device objects.  In our example, we
  76. do NOT have pairs for the GENERIC_DEVICE, BLOCK_DEVICE, or CHAR_DEVICE
  77. classes.
  78.  
  79. So your users would do this:
  80.  
  81.     #include <USER.H>    // contains all abstract base
  82.                 // class declarations, all enum decl's,
  83.                 // and prototypes for all MakeObject fns.
  84.                 // but **NOT** actual class decl's or
  85.                 // the definitions of MakeObject's
  86.  
  87.     // ...
  88.  
  89.         GENERIC_DEVICE *pgeneric = MakeObject(D_DISK_TYPE_1);
  90.         BLOCK_DEVICE *pblock = MakeObject(D_DISK_TYPE_1);
  91.         PRINTER *pprinter = MakeObject(D_PRINTER_TYPE_1);
  92.  
  93.         // the type of the enumerator selects the appropriate function
  94.  
  95.         // the pointer type returned might be to a derived class, but
  96.         // that's fine
  97.  
  98.         pgeneric -> reset();    // only generic functions
  99.         pblock -> readblock(...);    // generic and block functions
  100.         pprinter -> formfeed();    // generic, character, and printer functions
  101.  
  102. When you added a new device, you would:
  103.  
  104. 1.  Add the device ID to the appropriate enum in USER.H and add a case line to
  105.     the corresponding MakeObject function in your private files.
  106.  
  107. 2.  Add a class to handle the new device to your private files.
  108.  
  109. In addition, to add a new class of devices, you would:
  110.  
  111. 1.  Add a new enum and MakeObject declaration in USER.H and add the
  112.     MakeObject definition in your private files.
  113.  
  114. What do others think of this?
  115.  
  116. // Paul Johns
  117.