ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Понедельник
17 июня
237450 Топик полностью
AlexandrY (07.02.2011 21:39, просмотров: 182) ответил bialix-lazy на Ребята, у кого-то в загашниках остались исходники к статье Миро Самека про объектное программирование на Си?Оригинал жадные буржуи из журнала Embedded.com не хотят бесплатно давать или я сильно
Эти ? 
These are release notes to EPS 12'97 article "Portable Inheritance and 
Polymorphism in C". The source code listings follow a "Quick Reference" 
which explains steps necessary to implement particular OO concepts in C.
You will need the include file "object.h" and implementation file 
"object.c" to use in your projects. I provide also sample application
discussed briefly in the article. These files are marked as "sample
code".
In order to test the sample application you need to extract and save
as separate files : "object.h", "object.c", "string.h", "string.c",
"shapes.h", "shapes.c" and "test.c". They should compile and link 
without warnings. 

Miro Samek
miroslaw.samek@med.ge.com


Portable Inheritance and Polymorphism in C - Quick Reference
============================================================

   This document explains implementation of following 'design patterns'

   in C:

     * Encapsulation -- packaging data with functions into  classes  as
       well as techniques for information hiding and modularity,
   
     * Inheritance -- ability to define new classes and behavior  based
       on   existing   classes   to  obtain  code   re-use   and   code
       organization,

     * Polymorphism  --  the  same message sent  to  different  objects
       results  in  behavior that is dependent on  the  nature  of  the
       object receiving the message.
   
   This implementation adopts Java(tm) language approach to inheritance
   and  polymorphism.  Only  single class  inheritance  (implementation
   inheritance) is provided with 'Object' abstract class at the root of
   the  class  hierarchy.  In contrast, multiple interface  inheritance
   (type  inheritance) is provided allowing classes to  implement  many
   interfaces.


Abstract Base Class 'Object'
----------------------------
   The Object class is at the  root of the class hierarchy.  This class 
   encapsulates   virtual   pointer  and  defines  virtual   destructor 
   (inherited subsequently by all other classes). Constructor and  des-
   tructor are defined 'inline' as macros for efficiency. They are both
   protected (access to them is granted to  subclasses  only),  because 
   this class is intended solely for inheritance.  No 'Object'  objects 
   should be created by clients.
 
   This class declares also a couple of private methods  (some of  them
   are class methods, i.e. have no 'this' pointer).  These methods  are
   intended to use through macros only, since they require type casting,
   which is legitimate only in certain contexts. 

 Declaring Classes
 -----------------
   Classes are represented as structs of attributes. Class methods  are
   implemented as C functions taking as their first argument pointer to
   the attribute structure ('this' pointer). The class name is  mangled
   with method names.  A class must  always  extend  other  class  with
   Object at the root of the class hierarchy (single class inheritance).
 
     1. Use macro CLASS to start class declaration.
     2. Invoke  IMPLEMENTS  macro  for  each  interface  you  want   to
        implement by this class (optional).
     3. Declare attributes of the class (instance variables).
     4. Continue with macro VTABLE to declare  virtual  functions.  The
        arguments of macro VITABLE must be  identical as those used for
        corresponding macro CLASS.
     5. Invoke macro EXTENDS for each interface you declared with macro
        IMPLEMENTS.
     6. Declare  all function pointers for virtual methods you want  to
        introduce  in  this class (do not repeat the  abstract  methods
        declared  higher  in the hierarchy like the virtual  destructor
        'Des' inherited from 'Object').
     7. Continue with macro METHODS to declare class methods.
     8. Declare   prototypes  for  all  public  and  protected  methods
        implemented  by  the class. Apply naming convention  to  mangle
        class  name  with the operation name. Do not forget to  declare
        explicitly the 'this' argument for all methods (static or class
        methods do not need 'this' pointer).
     9. Close class declaration with macro END_CLASS.

   Example:
 
     #include "object.h"
 
     CLASS(Shape, Object)      /* class Shape extends Object         */
        IMPLEMENTS(Scaleable); /* and implements Scaleable interface */
        struct String name;    /* public name (object composition)   */
     VTABLE(Shape, Object)     /* Shape's VTABLE extends Object      */
        EXTENDS(Scaleable);    /* and also extends Scaleable         */
        double (*Area)(Shape); /* virtual method to compute area     */
     METHODS
        /* protected constructor (single '_' in the name) 
         * means that Shape is an abstract class 
         */
        Shape Shape_Con(Shape this, char *name);
        void Shape_Des(Shape this); /* protected destructor */
     END_CLASS
                          
                          
Declaring Interfaces
--------------------
   Interfaces are represented as structs of function pointers (VTABLEs)
   In that way interfaces declare only virtual  methods,  which must be
   eventually implemented by some classes. You can write code, however,
   which is unaware of any specific implementation and accesses objects
   solely through their  interfaces  (see macro ICALL).  Interfaces may
   extend other interfaces.
 
     1. Use INTERFACE macro to start interface declaration.
     2. Invoke  EXTENDS  macro for each interface you want  to  inherit
        from (optional).
     3. Declare  all  abstract  method  pointers  introduced  by   this
        interface.  Each method must declare first argument of 'Object'
        type.
     4. Close the declaration by END_INTERFACE macro.
 
   Example:
 
     #include "object.h"
 
     INTERFACE(Scaleable)
        void (*Scale)(Object, double);
     END_INTERFACE
 
     INTERFACE(Fooable)
        EXTENDS(Scaleable);   /* interface Fooable extends Scaleable */
        int (*Foo)(Object, long);
     END_INTERFACE
                          
                          
 Binding Virtual Functions
 -------------------------
   Virtual functions  are  declared  as  function  pointers  in a class
   descriptor (VTABLE)  associated  with  the  class.  VTABLEs  must be
   defined and initialized for every class. Since the inherited portion
   of VTABLE  is copied from  superclass only the newly introduced  and
   overridden virtual functions must be bound to their  implementation.
   This  is  done   by  assigning   implementation   functions  to  the
   corresponding function pointers.

     1. Use macro BEGIN_VTABLE to define class  descriptor  constructor
        for  a  given class.  Remember to invoke this  macro for  every
        class,  even  if  this  class does not  override  any  abstract
        methods. Otherwise the corresponding class descriptor  will  be
        undefined.
     2. Use  macro  VMETHOD  to bind abstract class  methods  to  their
        implementation.  For example  VMETHOD(Object,  Des)  refers  to
        abstract destructor introduced by the Object class. Remember to
        initialize all abstract method pointers introduced by the given
        class  (initialize 'purely virtual' functions with place holder
        Object_NoIm() method).
     3. Use  macro IMETHOD to bind abstract interface methods to  their
        implementation.  For example IMETHOD(Fooable.Scaleable,  Scale)
        refers to  abstract method 'Scale' from  'Scaleable'  interface
        which  is  extended  by  'Fooable'  interface.  Initialize  all
        abstract  method  pointers for interfaces  introduced  by  this
        class  (if the interfaces extend other interfaces the inherited
        methods  must  be  implemented  as  well).  Initialize  'purely
        virtual' functions with place-holder Object_NoIm() method.
     4. Close virtual table declaration with macro END_VTABLE.
 
   Example:
 
     #include "shape.h"
 
     BEGIN_VTABLE(Shape, Object)
        VMETHOD(Object, Des) = Shape_Des;       /* virtual destructor*/
        VMETHOD(Shape, Area) = Object_NoIm;     /* purely virtual    */
        IMETHOD(Scaleable, Scale) = Object_NoIm; /* ditto            */
     END_VTABLE
                     
                     
Defining Constructors
---------------------
   Each  class must provide at least one constructor method responsible
   for  initialization  of the attribute structure. Constructor  should
   take for the following actions:
 
     1. Call base class constructor.
     2. Invoke macro VHOOK to assign the virtual pointer.
     3. Invoke  macro  IHOOK for all interfaces for which you  override
        implementation (by invoking IMETHOD) in  corresponding  VTABLE.
     4. Initialize  class  attributes  (possibly  through   their   own
        constructors) in the order of their declaration in the class.
 
   Example:
 
     Shape Shape_Con(Shape this, char *name) {
        Object_Con(&this->super);      /* superclass constructor     */
        VHOOK(this, Shape);            /* assign 'Shape' VPTR        */
        IHOOK(this, Shape, Scaleable); /* assign 'Scaleable' VPTR    */
        if (!StringCon(&this->name, name))    /* construct member    */
           return NULL;                /* signal failure             */
        return this;                   /* signal success             */
     }
 

Defining Destructors
--------------------
   Optionally a class may define destructor implementation.  Destructor
   is responsible for releasing resources (memory, files ...) allocated
   during lifetime of an object (not only at construction).  If a class
   implements  destructor it  should  also  be  used  to  override  the
   inherited virtual destructor in the corresponding VTABLE. You should
   perform the following tasks in class destructors:
 
     1. Destroy attributes in the reverse order to their declaration in
        the class.
     2. Call superclass destructor.
 
   Example:
 
     void Shape_Des(Shape this) {
        StringDes(&this->name);   /* member destructor     */
        Object_Des(&this->super); /* superclass destructor */
     }                        

 
Invoking Virtual Class Methods
------------------------------
   Virtual   methods   are  called  indirectly  via   virtual   pointer
   referring to corresponding VTABLE.  Macros VCALL/END_CALL facilitate
   virtual class method invocation.
 
   Example:
     You can write code which only knows 'Shape' class.  The  area of a
     shape will be calculated through a virtual function call:
 
     #include "shape.h"
 
     void testShape(Shape s) {
        assert(IS_RUNTIME_CLASS(s, Shape)); /* use RTTI in assertion */
        printf("Shape.name=\"%s\", Shape.Area()=%.2f\n",
               StringToChar(&s->name),         /* static binding     */
               VCALL(s, Shape, Area)END_CALL); /* dynamic binding    */
     }
 
   A pointer to any object extending 'Shape' can be used as 'testShape'
   argument.  To be strictly correct you  should  cast  (upcast)  this
   pointer on the 'Shape' type.
 
     #include "shape.h"
 
     Circle c;
     ...
     testShape((Shape)c);
     ...

 
Invoking Virtual Interface Methods
----------------------------------
   Interfaces  require  additionally    resolving   reference  to   the
   implementing  object (I_TO_OBJ).  Macros  ICALL/END_CALL  facilitate
   virtual interface method invocation.
 
   Example:
     You can write code which only knows 'Scaleable' interface. Objects
     will be scaled through a virtual function  call  to  the   Scale() 
     method:
 
     #include "sclable.h"
 
     void testScaleable(Scaleable s) {               
        /* is it an Object?*/
        assert(IS_RUNTIME_CLASS(I_TO_OBJ(s), Object)); 
        
        printf("Scaleable.Scale(), ");
        ICALL(s, Scale) ,2.0 END_CALL;  /* dynamic binding */
     }
 
   Any object implementing 'Scaleable' can be used to  invoke  function
   'testScaleable'. If 'Circle' extends 'Shape' and 'Shape'  implements
   'Scaleable' you can say:
 
     Circle c;
     ...
     testScaleable(&c->super.Scaleable);
     ...


Handling Objects On The Heap:
-------------------------------
   1. Use macro ALLOC/DELETE to allocate and delete dynamic  objects,
      respectively.
   2. Use macro ALLOC_ARR/DELETE_ARR to allocate and delete arrays of
      dynamic object, respectively.
 
   Objects allocated with ALLOC/ALLOC_ARR  must still be  initialized
   by constructor call.  Macros DELETE/DELETE_ARR on  the other  hand
   perform complete cleanup calling  (virtual)  destructor  for  each
   object followed  by releasing heap memory.
 
   Example:
 
        Circ c = ALLOC(Circle);
        ...
        DELETE(c);
 
        Rect r = ALLOC_ARR(Rect, NRECT);
        ...
        DELETE_ARR(r);

 
Using RTTI (Run-Time Type Information):
---------------------------------------
   You can test objects for type compatibility using IS_RUNTIME_CLASS
   macro.  Do  not  misuse  RTTI  since it defeats polymorphism.  Use
   virtual functions instead.
 
   1. Macro IS_RUNTIME_CLASS returns 1 if run-time class of an object
      is, or inherits from a given class.
   2. Use macro I_TO_OBJ to obtain object reference from an interface
      reference.
 
   Example:
 
        Shape s;
        ...
        assert(IS_RUNTIME_CLASS(s, Shape));
 
        Scaleable s;
        ...
        assert(IS_RUNTIME_CLASS(I_TO_OBJ(s), Object));
 


LISTINGS
========

/**********************************************************************
 * object.h  -- interface of portable object oriented extension  to  C.
 *
 * @author M. Samek
 * @version 1.01, 03/20/97
 *
 * This header file defines the root base class 'Object' and macros for
 * declaring classes and  interfaces,  implementing  classes,  invoking
 * virtual  functions (dynamic binding), handling dynamic object on the
 * heap and a simple RTTI (run-time type information).
 * 
 */
#ifndef __OBJECT__

#include <stddef.h>  /* for size_t, ptrdiff_t and NULL */
#include <string.h>  /* for memcpy prototype */
#include <stdlib.h>  /* for malloc/free prototypes */
 
/**
 * Abstract base class 'Object'
 */
typedef struct Object *Object;
typedef struct ObjectClass *ObjectClass;
struct ObjectClass {
   size_t __size;       /* size of the Object instance */
   ObjectClass __super; /* superclass descriptor pointer */
   void (*Des)(Object);
};
extern struct ObjectClass __Object;
struct Object {
   ObjectClass __vptr; /* private virtual pointer */
}; 

/* protected constructor and destructor as macros */
#define Object_Con(this) {(this)->__vptr=&__Object; }
#define Object_Des(this) {}

/* Test for type compatibility, use through macro only */
int Object__IsKindOf(Object this, void *class);

/* Handling objects on the heap, use through macros only */
Object Object__AllocArr(size_t size, short dim);
void Object__DeleteArr(Object obj);
 
/* Dummy implementation for abstract methods */
void Object_NoIm(void);
  
/**
 * Macros for declaring classes
 */
#define CLASS(CX, SX)\
   typedef struct CX *CX;\
   struct CX {struct SX super;
#define IMPLEMENTS(IX) struct IX *IX
#define VTABLE(CX, SX) };\
   extern struct CX##Class __##CX;\
   typedef struct CX##Class *CX##Class;\
   struct CX##Class {struct SX##Class super;
#define METHODS };
#define END_CLASS

/**
 * Macros for declaring interfaces
 */
#define INTERFACE(IX) typedef struct IX **IX;\
   struct IX {ptrdiff_t __offset;
#define END_INTERFACE };
#define EXTENDS(IX) struct IX IX

/**
 * Macros for defining VTABLEs and binding virtual functions

 */
#define BEGIN_VTABLE(CX, SX) struct CX##Class __##CX;\
   static void CX##ClassCon(CX t){CX##Class vptr=&__##CX;\
   memcpy(vptr,((Object)t)->__vptr,sizeof(struct SX##Class));\
   ((ObjectClass)vptr)->__size=sizeof(struct CX);
#define VMETHOD(CX, MX) ((CX##Class)vptr)->MX
#define IMETHOD(IX, MX)\
   if (vptr->IX.__offset==0)\
      vptr->IX.__offset=(char*)&t->IX-(char*)t;\
   vptr->IX.MX
#define END_VTABLE\
   ((ObjectClass)vptr)->__super=((Object)t)->__vptr;}

/**
 * Macros needed in constructors
 */
#define VHOOK(OX, CX)\
   {if(((ObjectClass)&__##CX)->__size==0) CX##ClassCon(OX);\
   ((Object)(OX))->__vptr=(void*)&__##CX;}
#define IHOOK(OX, CX, IX) (OX)->IX=&__##CX.IX
 
/**
 * Macro for invoking virtual class methods
 * and macro for invoking interface methods.
 */
#define VCALL(OX, CX, MX)\
   (*((CX##Class)(((Object)(OX))->__vptr))->MX)((CX)(OX)
#define ICALL(IPX, MX) (*(*(IPX))->MX)(I_TO_OBJ(IPX)
#define END_CALL )

/**
 * Macros for handling objects on the heap
 */
#define ALLOC(CX)  (CX)malloc(sizeof(struct CX))
#define DELETE(OX)\
   {VCALL(OX, Object, Des)END_CALL; free((void*)(OX));}
#define ALLOC_ARR(CX,DX)\
   (CX)Object__AllocArr(sizeof(struct CX), DX)
#define DELETE_ARR(OX)  Object__DeleteArr((Object)(OX))

/**
 * Macros for RTTI (Run-Time Type Information)
 */
#define IS_RUNTIME_CLASS(OX, CX)\
   Object__IsKindOf((Object)(OX),(void*)&__##CX)
#define I_TO_OBJ(IPX) (Object)((char*)(IPX)-(*(IPX))->__offset)

#define __OBJECT__
#endif

/********************************************************************** 
 * object.c -- implementation file for Object class and utilities
 * @author  M. Samek
 * @version 1.01, 03/20/97
 */
#include "object.h"

#include <assert.h>

/** implementation of Object class */
struct ObjectClass __Object = { 
   sizeof(struct Object),        /* size of Object attributes */
   NULL,                         /* no superclass */
   (void (*)(Object))Object_NoIm /* purely virtual destructor */
};

int Object__IsKindOf(Object this, void *class) {
   ObjectClass c;
   for (c = this->__vptr; c; c = c->__super)
      if (c == class)
         return 1;
   return 0;
}

Object Object__AllocArr(size_t size, short dim) {
   short *a = (short*)malloc(sizeof(short)+dim*size);
   if (a == NULL)
      return NULL;
   *a = dim; /* store the array dimension */
   return (Object)(a + 1); /* return loaction of the first object */
}

void Object__DeleteArr(Object pobj) {
   short *a = (short*)pobj - 1; /* start of allocated memory */
   size_t s = ((ObjectClass)pobj->__vptr)->__size;
   char *p; /* location of an object */
   short i; /* index into the array */
   for (i = 0, p = (char*)pobj; i < *a; i++, p += s)
      VCALL(p, Object, Des)END_CALL;
   free((void*)a); /* free up memory */
}

void Object_NoIm(void) {
   assert(0); /* break the execution */
}

/********************************************************************** 
 * string.h -- sample code
 * @author  M. Samek
 * @version 1.00, 03/06/97
 */
#ifndef __STRING__

#include "object.h"

/** String class extends Object */
CLASS(String, Object)
   char *__buffer; /* private character buffer */
VTABLE(String, Object)
METHODS
   /* public constructors */
   String StringCon1(String this, const char *str);
   String StringCon2(String this, String other);

   /* public destructor */
   void StringDes(String this);

   /* public to char conversion */
   const char *StringToChar(String this);

END_CLASS

#define __STRING__
#endif

/********************************************************************** 
 * string.c -- sample code
 * @author  M. Samek
 * @version 1.00, 03/06/97
 */
#include "string.h"

#include <stdlib.h>
#include <string.h>

/** implementation of String */
BEGIN_VTABLE(String, Object)
   VMETHOD(Object, Des) = (void (*)(Object))StringDes;
END_VTABLE

String StringCon1(String this, const char *str) {
   Object_Con(&this->super); /* construct superclass  */
   VHOOK(this, String); /* hook on the String class */
   
   /* allocate and initialize the character buffer */                   
   this->__buffer = (char*)malloc(strlen(str) + 1);
   if (!this->__buffer)
      return NULL;      /* failure */
   strcpy(this->__buffer, str);
   return this;
}

String StringCon2(String this, String other) {
   return StringCon1(this, StringToChar(other));
}

const char *StringToChar(String this) {
   return this->__buffer;
}

void StringDes(String this) {
   free(this->__buffer);     /* release buffer */ 
   Object_Des(&this->super); /* destroy superclass */
}

/********************************************************************** 
 * shapes.h -- sample code
 * @author  M. Samek
 * @version 1.00, 03/06/97
 */
#ifndef __SHAPES__

#include "object.h"
#include "string.h"

/** Interface Scaleable */
INTERFACE(Scaleable)
   void (*Scale)(Object, double); 
END_INTERFACE

/** Class Shape extends Object, implements Scaleable */
CLASS(Shape, Object) IMPLEMENTS(Scaleable);
   struct String name;     /* public shape's name */
VTABLE(Shape, Object) EXTENDS(Scaleable);
   double (*Area)(Shape);  /* pure virtual! */
METHODS
   Shape Shape_Con(Shape this, char *name);
   void Shape_Des(Shape this);
END_CLASS

/** Class Rect extends Shape */
CLASS(Rect, Shape)
   double __w; /* private width  */
   double __h; /* private height */
VTABLE(Rect, Shape)
METHODS
   Rect RectCon(Rect this, char *name, double w, double h);
   double RectArea(Rect this);
   void RectScale(Rect this, double mag);
END_CLASS

/** Class Circle extends Shape */
CLASS(Circle, Shape)
   double __r; /* private radius */
VTABLE(Circle, Shape)
METHODS
   Circle CircleCon(Circle this, char* name, double r);
   double CircleArea(Circle this);
   void CircleScale(Circle this, double mag);
END_CLASS

#define __SHAPES__
#endif

/********************************************************************** 
 * shapes.c -- sample code
 * @author  M. Samek
 * @version 1.00, 03/06/97
 */
#include "shapes.h"

/** implementation of Shape */
BEGIN_VTABLE(Shape, Object)
   VMETHOD(Object, Des) = (void (*)(Object))Shape_Des;
   VMETHOD(Shape, Area) = (double (*)(Shape))Object_NoIm;
   IMETHOD(Scaleable, Scale) = (void (*)(Object, double))Object_NoIm;
END_VTABLE

Shape Shape_Con(Shape this, char *name) {
   Object_Con(&this->super);      /* construct superclass */
   VHOOK(this, Shape);            /* hook Shape class */
   IHOOK(this, Shape, Scaleable); /* hook Scaleable interface */
   if (!StringCon1(&this->name, name)) /* construct member */
      return NULL;                /* report failure */
   return this;
}

void Shape_Des(Shape this) {
   StringDes(&this->name);   /* destroy member     */
   Object_Des(&this->super); /* destroy superclass */
}

/** implementation of Rect  */
BEGIN_VTABLE(Rect, Shape)
   VMETHOD(Shape, Area) = (double (*)(Shape))RectArea;
   IMETHOD(super.Scaleable, Scale) = (void (*)(Object,
double))RectScale;
END_VTABLE

Rect RectCon(Rect this, char *name, double w, double h) {
   if (!Shape_Con(&this->super, name)) /* construct superclass */
      return NULL;                     /* report failure */
   VHOOK(this, Rect);                  /* hook Rect class */
   IHOOK(this, Rect, super.Scaleable); /* hook Scaleable interface */
   this->__h = h;                      /* initialise member(s) */
   this->__w = w;
   return this;
}

double RectArea(Rect this) {
   return this->__w  *this->__h;
}

void RectScale(Rect this, double mag){
   this->__w *= mag;
   this->__h *= mag;
}

/* implementation of Circle */
BEGIN_VTABLE(Circle, Shape)
   VMETHOD(Shape, Area) = (double (*)(Shape))CircleArea;
   IMETHOD(super.Scaleable, Scale) = (void (*)(Object,
double))CircleScale;
END_VTABLE

Circle CircleCon(Circle this, char *name, double r) {
   if (!Shape_Con(&this->super, name))/* construct superclass */
      return NULL;                    /* report failure */
   VHOOK(this, Circle);               /* hook Circle class */
   IHOOK(this, Circle, super.Scaleable); /* hook Scaleable interface */
   this->__r = r;                     /* initialise member(s) */
   return this;
}

double CircleArea(Circle this) {
   return 3.14 * this->__r * this->__r;
}

void CircleScale(Circle this, double mag) {
   this->__r *= mag;
}
    
/********************************************************************** 
 * test.c -- sample code
 * @author  M. Samek
 * @version 1.00, 03/06/97
 */
#include "shapes.h"

#include <stdio.h>
#include <assert.h>

void testShape(Shape s) {
   assert(IS_RUNTIME_CLASS(s, Shape));
   printf("Shape.name=\"%s\", Shape.Area()=%.2f\n",
          StringToChar(&s->name),         /* static binding */
          VCALL(s, Shape, Area)END_CALL); /* dynamic binding */
}

void testScaleable(Scaleable s) {
   assert(IS_RUNTIME_CLASS(I_TO_OBJ(s), Object)); 
   printf("Scaleable.Scale(), ");
   ICALL(s, Scale) ,2.0 END_CALL; /* dynamic binding */
}

#define NRECT 10

void main() {
   struct Circle circle;  /* Circle instance on the stack frame */
   Circle c;
   Rect r; 
   int i;

   /* construct objects... */
   c = CircleCon(&circle, "Circle", 0.5); /* construct a Circle */
   r = ALLOC_ARR(Rect, NRECT); /* allocate Rectangles */ 
   for (i = 0; i < NRECT; i++) {
      char name[20];
      sprintf(name, "Rectangle-%d", i); /* prepare the name */
      RectCon(&r[i], name, (double)i, 0.5); /* construct a Rect */
   }

   /* test each object... */
   testScaleable(&c->super.Scaleable);
   testShape((Shape)c);
   for (i = 0; i < NRECT; i++) {
      testScaleable(&r[i].super.Scaleable);
      testShape((Shape)&r[i]);
   }

   /* detstroy objects... */
   VCALL(c, Object, Des)END_CALL;  /* dynamic binding */
   DELETE_ARR(r);
}
    




Listing 1
Declaration of String class.

#include 3object.h2
/** Character String class */
CLASS(String, Object)
   char *__buffer; /* private buffer */
VTABLE(String, Object)
METHODS
   /* public constructors */
   String StringCon1(String this,
                const char *str);
   String StringCon2(String this,
                String other);

   /* public destructor *
   void StringDes(String this);

   /* public to char conversion */
   const char *StringToChar(String this);
END_CLASS


Listing 2
Definition of class String.

#include <stdlib.h>
#include <string.h>
#include 3string.h2
/** implementation of String class */
BEGIN_VTABLE(String, Object)
   VMETHOD(Object, Des) = (void (*)(Object))StringDes;
END_VTABLE
String StringCon1(String this, const char *str) {
   Object_Con(&this->super); /* construct superclass */
   VHOOK(this, String);   /* hook String VPTR */
   /* allocate and initialize the buffer */
   this->__buffer = (char*)malloc(strlen(str) + 1);
   if (!this->__buffer)
      return NULL;      /* failure */
   strcpy(this->__buffer, str);
   return this;
}
String StringCon2(String this, String other) {
   return StringCon1(this, StringToChar(other));
}
const char *StringToChar(String this) {
   return this->__buffer;
}
void StringDes(String this) {
   free(this->__buffer);   /* release buffer */
   Object_Des(&this->super); /* destroy superclass */
}



INDEMSYS