Single Inheritance Classes in C
by Ron Kreymborg

Example 1:

typedef struct
{
    //----------------------------------------------
    // Set a copy of the port address to use.
    void (*InitPort)(MotorData*, int*);

    //----------------------------------------------
    // Set/Get the motor speed.
    void (*SetSpeed)(MotorData*, int);
    int (*GetSpeed)(MotorData*);

    //----------------------------------------------
    // Set/Get the motor rotation direction.
    void (*SetDirection)(MotorData*, DIRECTION);
    DIRECTION (*GetDirection)(MotorData*);
} MOTOR;


Example 2:

(a)
static const MOTOR cMotor = {
  InitPort,
  SetSpeed,
  GetSpeed,
  SetDirection,
  GetDirection
};
MOTOR* Motor;


(b)
MotorData* MotorCtor(void)
{
    MotorData* d;

    // Create the data structure and 
    // initialize the contents.
    d = Allocate(sizeof(MotorData));
    d->mPort = NULL;
    d->mSpeed = 0;
    d->mDirection = DR_UNKNOWN;

    // Create the vtable by copying it to RAM.
    if (InstCount++ == 0)
    {
        CREATE_VTABLE(Motor, cMotor, MOTOR);
    }
    return d;
}

Example 3:

void MotorXtor(MotorData* d)
{
    if (d)
    {
        *d->mPort = 0;    // ensure motor stopped
        Free(d);
        DestroyVtable(Motor, &InstCount);
    }
}

Example 4:

(a)
typedef struct
{
  MotorData  mMotor;
  int        mAccelRate;
} MotorControlData;


(b)
typedef struct
{
    //----------------------------------------------
    // Set the new speed and an accel/decel rate to
    // reach that speed.
    void (*SetNewSpeed)(MotorControlData*, int speed, int rate);

    //----------------------------------------------
    // Base class Motor methods extracted from its typedef.
    void (*InitPort)( MotorData*, int*);
    void (*SetSpeed)(MotorData*, int);
    int (*GetSpeed)(MotorData*);
    void (*SetDirection)(MotorData*, DIRECTION);
    DIRECTION (*GetDirection)(MotorData*);
} MOTOR_CONTROL;

extern MotorControlData* MotorControlCtor(void);
extern void MotorControlXtor(MotorControlData*);
extern MOTOR_CONTROL* MotorControl;

Example 5:

MotorData* MotorCtor(void* data, void(**v)())
{
    MotorData* d;
    if (data)
    {
        // This is the base class for a defined class.
        // The caller has defined both their own data 
        // structure and vtable.
        d = data;
        if (v)
        {
            *v++ = InitPort;
            *v++ = SetSpeed;
            *v++ = GetSpeed;
            *v++ = SetDirection;
            *v++ = GetDirection;
        }
    }
    else
    {
        // This is a stand-alone class, and both the 
        // data structure and vtable must be created here.
        d = Allocate(sizeof(MotorData));
        if (InstCount++ == 0)
        {
            CREATE_VTABLE(Motor, cMotor, MOTOR);
        }
    }

    // Initialize the class data.
    d->mPort = NULL;
    d->mSpeed = 0;
    d->mDirection = DR_UNKNOWN;

    return d;
}

Example 6:

MotorControlData* MotorControlCtor(void* q, void (**v)(void))
{
    MotorControlData* d;
    d = Allocate(sizeof(MotorControlData));
    d->mAccelRate = 0;

    if (InstCount++ == 0)
    {
        CREATE_VTABLE(MotorControl, cMotorControl, MOTOR_CONTROL);
        MotorCtor(p, &MotorControl->InitPort);
    }
    else
    {
        MotorCtor(p, NULL);
    }
    return d;
}



Listing One

/******************************************************************************
   PROJECT  C Classes
   NAME     C_Classes.h
   PURPOSE  A header file for C classes derived using the C_Class methods.
   AUTHOR   Ron Kreymborg, Jennaron Research
******************************************************************************/
#ifndef _C_CLASSES_H
#define _C_CLASSES_H

#include <stdlib.h>
#include <memory.h>

#define TRUE        1
#define FALSE       0
//-----------------------------------------------------------------------------
// A macro to copy the vtable structure in rom into ram. The VECTOR parameter
// is the destination structure pointer, and the STRUCTURE parameter is a
// pointer to the source vector table. Note that sizeof will ensure there is
// space for all functions defined in the typedef.
//
#define CREATE_VTABLE(VECTOR, STRUCTURE, TYPEDEF) \
        VECTOR = (TYPEDEF*)Allocate(sizeof(TYPEDEF)); \
        memcpy(VECTOR, &STRUCTURE, sizeof(TYPEDEF))
/*
If you want to replace the macro with a function, here is the
required prototype...
void CREATE_VTABLE(void** to, void* from, int size);
*/
//-----------------------------------------------------------------------------
// Free the vtable heap memory based on useage. Both parameters are pointers.
//
extern void DestroyVtable(void*, int*);
//-----------------------------------------------------------------------------
// Allocate space from the heap.
//
extern void* Allocate(int);
//-----------------------------------------------------------------------------
// Return the memory to the heap.
//
extern void Free(void*);
//-----------------------------------------------------------------------------
// Return the current count of allocated items on the heap. Call when the
// process completes to check if all classes have been correctly shutdown.
//
extern int DataCount(void);

#endif  // _C_CLASSES_H


Listing Two

/******************************************************************************
   PROJECT  C Classes
   NAME     C_Classes.c
   PURPOSE  The C_Classes vtable heap allocation and de-allocation methods.
   AUTHOR   Ron Kreymborg, Jennaron Research
******************************************************************************/
#include <stdio.h>
#include "C_Classes.h"

static int mDataCount;
//-----------------------------------------------------------------------------
// Destroy the vtable based on whether the instance count goes to zero.
//
void DestroyVtable(void* structure, int* count)
{
    if (--(*count) == 0)
    {
        Free(structure);
    }
}
//-----------------------------------------------------------------------------
// Remove a heap structure.
//
void Free(void *p)
{
    mDataCount--;
    free(p);
}
//-----------------------------------------------------------------------------
// Allocate the requested bytes from the heap.
//
void *Allocate(int size)
{
    void *p = malloc(size);
    if (p)
    {
        mDataCount++;
        return p;
    }
    else
    {
        // The heap space is exhausted. Provide an error handler here. Do NOT
        // ever return from here unless the heap has been enlarged. Put a
        // suitable error handler here that matches the processor environment
        // requirements.
        //
        printf("Out of heap memory");
        while(1) {;}
    }
}
//-----------------------------------------------------------------------------
// Return the number of outstanding heap allocations.
//
int DataCount(void)
{
    return mDataCount;
}




