home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / code / tcopuls_.sit / README < prev    next >
Encoding:
Text File  |  1989-10-03  |  15.7 KB  |  428 lines  |  [TEXT/EDIT]

  1. /*    README - Portable C++/THINK C 4.0 Object programs
  2.  
  3.     Copyright (C) 1989, Integrity Software
  4.     Author: Isaac J. Salzman (salzman@rand.org)
  5.  
  6.     This software may be freely used/modified/distributed
  7.     as desired so long as this copyright notice remains
  8.     in tact.
  9.  
  10.     $Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/README,v 1.2 89/10/03 00:32:58 salzman Exp Locker: salzman $
  11.  
  12.     $Log:    README,v $
  13. # Revision 1.2  89/10/03  00:32:58  salzman
  14. # added note about virtual destructors
  15.     Revision 1.1  89/09/17  15:01:41  salzman
  16.     Initial revision
  17.      
  18. */
  19.  
  20. The contents of this archive are as follows:
  21.  
  22.     README        - this file
  23.     class.h        - macros for portable C++/THINK C object programs
  24.     
  25.     link.h        - a Link class for implementing linked lists: header
  26.     link.c        - and implementation
  27.     intlink.h    - IntLink class - linked list of int's: header
  28.     intlink.c    - and implementation
  29.     strlink.h    - StrLink class - linked list of strings: header
  30.     strlink.c    - and implementation
  31.     listlink.h    - ListLink class - linked list of Link's: header
  32.     listlink.c    - and implementation
  33.     linktest.c    - a test program for the above classes
  34.     
  35. All documentation is contained in this file. Please read this before
  36. attempting to use class.h. The macros are not nearly as important as
  37. the contents of this file.
  38.  
  39. The enclosed "class.h" file contains a set of C pre-processor macros to aid
  40. in the development of source code that is portable between THINK C 4.0
  41. objects and C++. By using these macros and following certain coding
  42. conventions, source code may be compiled and run under THINK C 4.0 or C++
  43. without modification. These macros have been tested with GNU C++ 1.35,
  44. and Oasys C++ (which is basically a port of AT&T cfront 1.2). NOTE: The
  45. Oasys cpp is broken -- use the @n option with Oasys to use the standard
  46. cpp.
  47.  
  48. If you start with the goal of portability in mind it is quite easy to
  49. accomplish. If you try and apply it to already developed C++ code or THINK
  50. C object code, you will no doubt encounter difficulties (more so when
  51. starting with C++).
  52.  
  53. Before I get in to the macros, I just want to address some general
  54. issues of portability between THINK C Objects (TCO) and C++.
  55.  
  56. First off, objects in TCO are always pointers - you can't just
  57. declare something:
  58.  
  59.     Class foo;
  60.  
  61. you must declare it as
  62.  
  63.     Class *foo;
  64.  
  65. and then call the initialization method in order to instantiate it:
  66.  
  67.     foo = MakeObject(Class)( /* args to init method/constructor */ );
  68.  
  69. In C++ this is just like saying
  70.  
  71.     foo = new Class (/* args */ );
  72.  
  73. Details on what's done in TCO are in the description of the relevant
  74. macros below. The main point: always use pointers to objects (if you
  75. want to be portable)!
  76.  
  77. Method overloading: TCO doesn't have it. Yes, this is a bummer.
  78. Though it's one of the better ideas in C++, it's something you
  79. can live without if you want portability. Methods of the same name
  80. in derived classes must take the same type and number of arguments
  81. as defined in the super class in TCO. One way to deal with that is 
  82. to use <stdarg.h> and declare things like this:
  83.  
  84.     #include <stdarg.h>
  85.     
  86.  
  87.     int method ( ... );
  88.     
  89. Of course you have to deal with parsing the arg's instead of having
  90. the compiler figure out what to do.
  91.  
  92. Comments: only use /* */, TCO doesn't know about //.
  93.  
  94. Header files: THINK C has <stdlib.h> which must be included if you're
  95. using routines that are part of the ANSI C defined standard library.
  96. You'll have to include different header files for C++ depending on
  97. implementation (<std.h> for g++ for example).
  98.  
  99. O/S portability is a whole 'nother issue. Real Mac programs don't use
  100. stdio. Those are issues which you'll have to deal with. If someone wants
  101. to port the THINK C class library to C++ and X11, that would be great!!
  102.  
  103. I've probably left some stuff out, but those are the important issues.
  104. And now on with the macros....
  105.  
  106. ----------------------------------------------------------------------
  107.  
  108. Description
  109.  
  110. The definition for each macro is shown for both THINK C Objects (TCO), and
  111. C++ followed by a brief explanation of its usage.
  112.  
  113. TCO: #define class struct
  114. C++: /* none */
  115.  
  116.      Simply define class to struct for TCO. TCO does not have a "class"
  117.      keyword, (and in actuality, struct may be used in place of class in C++
  118.      as well).
  119.  
  120. TCO: #define virtual
  121. C++: /* none */
  122.  
  123.      There is no "virtual" keyword in TCO since all methods are virtual.
  124.      Simply define this as nothing.
  125.  
  126. TCO: #define PRIVATE
  127.      #define PROTECTED
  128.      #define PUBLIC
  129.  
  130. C++: #define PROTECTED protected:
  131.      #define PRIVATE private:
  132.      #define PUBLIC public:
  133.  
  134.      TCO makes no distinction between private, public and protected
  135.      members. All members are public according to TCO. These macros are to
  136.      be used in place of the labels normally used in C++. Do NOT include
  137.      the colon ":", it's part of the macro.
  138.  
  139. TCO: #define ROOT : indirect /* this can also be : direct, read the THINK C
  140.                 manual for a desc. of the difference */
  141. C++: #define ROOT
  142.  
  143.      TCO determines if a struct is a class by looking at wether or not it
  144.      inherits from something. ALL classes in TCO must inherit from
  145.      *somthing*, otherwise they're just normal C structs. A root class in
  146.      TCO inherits from either "indirect" or "direct". Details on this
  147.      are explained in TC manual (it has to do with memory management and
  148.      wether handles or pointers are used). When declaring a root class,
  149.      declare as follows:
  150.  
  151.      class some_root_class ROOT
  152.      {
  153.         /* variables, method declartions */
  154.      };
  155.  
  156. TCO: #define INHERIT_PUBLIC
  157. C++: #define INHERIT_PUBLIC public
  158.  
  159.      C++ requires that you explicitly declare wether or not public members
  160.      of a base class are to be made public in a derived class. The default
  161.      (for C++) is that these become private members of the derived class
  162.      (and therefor can not be called by clients of this class).
  163.      This does nothing in TCO since everything is essentially public.
  164.      Example usage:
  165.  
  166.      class Derived INHERIT_PUBLIC : BaseClass
  167.      {
  168.     /* stuff */
  169.      }
  170.  
  171. TCO: #define PREDEC_CLASS(Class)
  172. C++: #define PREDEC_CLASS class Class
  173.  
  174.      If you're defining classes that need to refer to themselves (common
  175.      for doing linked lists and such). I don't think you really need this
  176.      at all (and I haven't tested it really). Instead, just preceed members
  177.      of a class which will have the same type as the class currently being
  178.      defined, with "class". [yeah, it's confusing].
  179.  
  180. [the following macros deal with constructors/initialization]
  181.  
  182. TCO: #define DECL_INIT(Class) Class *Init##Class
  183. C++: #define DECL_INIT(Class) Class
  184.  
  185.      [NOTE: the ## in the macro has the effect of performing string
  186.      catenation. this is a handy for declaring initialize methods that have
  187.      unique names for each class, which makes life much easier].
  188.  
  189.      These macros are used for DECLaring constructors/initialize methods in
  190.      C++/TCO respectively. Example usage:
  191.  
  192.      class Derived INHERIT_PUBLIC : BaseClass
  193.      {
  194.  
  195.     /* stuff */
  196.  
  197.         DECL_INIT(Derived)(/* args */);
  198.      };
  199.  
  200.      In C++ this will expand to:
  201.  
  202.         Derived(/* args     */);
  203.  
  204.      In TCO this will be:
  205.  
  206.     Derived *InitDerived(/* args */);
  207.  
  208.      There's no special method for doing initialization in TCO. In C++
  209.      you must declare a constructor which is called everytime you
  210.      instantiate an object of that class. This happens automatically. We
  211.      can duplicate this behavior by the use of this macro and others to
  212.      follow. Also, notice that there is no return type for the C++
  213.      constructor. It's implicitly defined as returning an object (or
  214.      pointer to an object) of that class. It can't be redefined. In TCO we
  215.      need to declare this as always returning a pointer to that object (you
  216.      can't declare objects in TCO, just pointers to objects). More on this
  217.      follows.
  218.  
  219. TCO: #define DEF_INIT(Class) Class *Class::Init##Class
  220.      #define INIT_SUPER(Class,args) Class::Init##Class args
  221.      #define SUPER_INIT_ARGS(args)
  222.      #define RETURN_THIS return this
  223.  
  224. C++: #define DEF_INIT(Class) Class::Class
  225.      #define SUPER_INIT_ARGS(args) : args
  226.      #define INIT_SUPER(Class,args)
  227.      #define RETURN_THIS
  228.      
  229.      These are used when actually defining the constructor/initialization
  230.      method. Example:
  231.  
  232.      DEF_INIT(Derived)( /* args */ ) SUPER_INIT_ARGS(( /* super args */ ))
  233.      {
  234.     /* code */
  235.  
  236.     INIT_SUPER(BaseClass, (/* super args */));
  237.  
  238.     RETURN_THIS;
  239.      }
  240.  
  241.      which ends up to be (for TCO):
  242.  
  243.      Derived *Derived::InitDerived ( /* args */ )
  244.      {
  245.     /* code */
  246.  
  247.     BaseClass::InitBaseClass (/* super args */);
  248.     return this;
  249.      }
  250.  
  251.      and this (for C++):
  252.  
  253.      Derived::Derived ( /* args */ ) : ( /* super args */ )
  254.      {
  255.     /* code */
  256.  
  257.     ;
  258.     ;
  259.      }
  260.  
  261.      Yes this looks kludgy, but it does the job! There are 4 macros
  262.      involved here: DEF_INIT for defining the constructor/initialization
  263.      method, SUPER_INIT_ARGS for passing arguments up to the super class
  264.      (the thing that this inherits from --  only relevant to C++),
  265.      and INIT_SUPER for calling the super classes's initialize method (only
  266.      relevant to TCO). RETURN_THIS is needed for TCO since we're going
  267.      to assign whatever is returned from the initialization method to
  268.      the pointer to the object we're instantiating. You can just put
  269.      "return this;" in there, but C++ will complain with a warning
  270.      message.
  271.      
  272.      Initialization is where TCO and C++ diverge the most and where
  273.      you need to be a bit kludgy and verbose in order to be portable. But,
  274.      it's worth the effort! Depending on wether you're using C++ or TCO,
  275.      only one of INIT_SUPER or SUPER_INIT_ARGS will actually result in any
  276.      code being generated from the macros. 
  277.  
  278.      Things to be careful about: you must enclose (args) in paren's as
  279.      shown, or the macros will break. The last line in this method must be
  280.      "RETURN_THIS;" in order for TCO initialization to work properly. You
  281.      only need SUPER_INIT_ARGS if the super class takes arguments. This is
  282.      one of the more arcane constructs of C++. 
  283.  
  284. TCO: #define MakeObject(Class) ((Class *)new (Class))->Init##Class
  285. C++: #define MakeObject(Class) new Class
  286.  
  287.      And here's how to make an instance of the object:
  288.  
  289.     Derived *dp;  /* declare a ptr to the object */
  290.  
  291.     dp = MakeObject(Derived)( /* args */ );         /* instantiate it */
  292.  
  293.      which will end up as (in TCO):
  294.  
  295.     dp = ((Derived *) new (Derived))->InitDerived ( /* args */ )
  296.  
  297.      and (in C++):
  298.  
  299.     dp = new Derived ( /* args */ );
  300.  
  301.     TCO does not call any initialization method automatically upon
  302.     instantiation as C++ does. But we can still do it in the same step, and
  303.     hide the details in a macro. So as far as you're concerned, it always
  304.     gets done. The syntax of calling the initialize method at the same
  305.     time as instantiating the object in TCO is out of the TC User's
  306.     Manual. But again, it's tucked away in a macro, so how it's done
  307.     shouldn't really matter, right?
  308.  
  309. [and now all the destructor/destroy method stuff]
  310.  
  311. TCO: #define DECL_DEST(Class) void Destroy
  312.      #define DEF_DEST(Class)  void Class::Destroy
  313.      #define DestroyObject(Object) { Object->Destroy();delete(Object); }
  314.      #define DESTROY_SUPER inherited::Destroy()
  315.      
  316. C++: #define DECL_DEST(Class) virtual ~Class
  317.      #define DEF_DEST(Class) Class::~Class
  318.      #define DestroyObject(Object) delete Object
  319.      #define DESTROY_SUPER
  320.  
  321.      These macros define the destroy/destructor methods for TCO and C++.
  322.      Example usage:
  323.  
  324.        class Derived : INHERIT_PUBLIC SuperClass
  325.        {
  326.         /* stuff */
  327.  
  328.         DECL_DEST(Derived)( /* args */ );
  329.        }
  330.  
  331.        DEF_DEST(Derived)( /* args */ )
  332.        {
  333.         /* code */
  334.         
  335.         DESTROY_SUPER;
  336.        }
  337.  
  338.        /* and to get rid of something */
  339.  
  340.        Derived *dp;
  341.  
  342.        DestroyObject(dp);
  343.  
  344.      These macros are pretty straight forward. Things to watch out for:
  345.      I've chosen to call all destroy methods Destroy() in TCO. This means
  346.      that they must always take the same number of and type of arguments
  347.      for all derived classes. Since these methods rarely take arguments,
  348.      I chose to stick with this convention. If you want to append the 
  349.      class name in TCO, no problem: just use Destroy##Class, but then
  350.      you'd have to pass the class name as an argument as well....
  351.  
  352.  
  353.      C++ automatically calls virtual destructors up the inheritance 
  354.      hierarchy. TCO doesn't (it's just another method in TCO), 
  355.      therefore you need to use DESTROY_SUPER in TCO -- which just 
  356.      calls the super classes  Destroy() method, and does nothing in C++.
  357.  
  358.      NOTE: destructors MUST be declared virtual in C++ in order for
  359.      them to have compatible behaviour with TCO. There are some
  360.      obscure instances where complete compatability is impossible.
  361.      If you call a virtual destructor for a derived class, it will
  362.      work its way up the hierarchy calling destructors for each
  363.      base class. As it leaves a destructor, the object does not belong
  364.      to that class anymore. It changes its identity along the way. The
  365.      result is that if you're calling virtual methods in your destructors,
  366.      you will not get the expected results. Since, in TCO, the Destroy 
  367.      method is like any other method, it does not have this odd side 
  368.      effect. It turns out that Cfront 1.2 is broken in this respect
  369.      whereas GNU C++ does the right thing (I found this out while
  370.      reporting what I thought may have been a bug in g++).
  371.  
  372. ------------------------------------------------------------------------
  373.  
  374. The Example Program
  375.  
  376. As an example, I've created a Link class which is used to create linked
  377. lists. This is not intended to be the worlds best or most efficient 
  378. implementation of a linked list class, but I happen to find it useful
  379. for my work, and it serves as a good example for using the class.h macros.
  380.  
  381. First off, the Link class is not to be used by itself, but to be inherited
  382. from. It implements some basic funtions: append, prepend, insert and find.
  383. Those names should be self explanitory. These need not be redifined for
  384. sub-classes, though you can if you want. There is a compare method which
  385. is used by find and insert. For simplicity, it always takes a string  (char *)
  386. as an argument and is used to find a link by name. The showval method is also
  387. virtual and defined for sub-classes and is used to print the contents of
  388. the current link.
  389.  
  390. A link has a next, previous and tail pointer (i.e. it's doubly-linked).
  391. In order for prepend to work properly, the first link (the head) never
  392. changes. That would require assigning to "this", which, as far as i'm
  393. concerned, is BAD news (and in fact not supported in cfront 2.0 or current
  394. g++ implementations). So the head link doesn't contain any useful data
  395. except for a pointer to the tail and a pointer to the real first link in
  396. the list (the next pointer).
  397.  
  398. There are three sub-classes of Link: IntLink a list of integers, StrLink:
  399. a list of strings (char *'s), and ListLink: (which is derived from StrLink),
  400. a list of links. The example program creates 2 lists, each containing a
  401. mixture of StrLinks and IntLinks, and then creates a ListLink which contains
  402. those 2 lists. The lookup method (only in the ListLink class), is used to
  403. search for an item by name in any of the lists contained in the ListLink, or
  404. to search for the a list with that name. Yes this is confusing -- look at
  405. the source code!!!
  406.  
  407. To build the example:
  408.  
  409.     - Use the Makefile for UNIX and C++.
  410.  
  411.     - Create a THINK C project with all the .c files and the
  412.       ANSI and oops libraries.
  413.  
  414. ----------------------------------------------------------------------------
  415.  
  416. If you have any questions, feel free to send me e-mail. And, if you've got
  417. some suggestions and improvements, please send them along!! I hope someone
  418. finds this stuff useful. Enjoy!!
  419.  
  420. * Isaac J. Salzman                          ----     
  421. * The RAND Corporation - Information Sciences Dept.         /o o/  /  
  422. * 1700 Main St., PO Box 2138, Santa Monica, CA 90406-2138    | v |  |  
  423. * AT&T        : +1 213-393-0411 x6421 or x7923 (ISL lab)        _|     |_/   
  424. * Internet  : salzman@rand.org                   / |     |
  425. * UUCP        : !uunet!rand.org!salzman               | |     |     
  426. * CompuServe: 76167,1046
  427.