Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

Single Inheritance Classes in C


The Destructor

The code for a normal destructor is straightforward. If the data pointer is valid, the motor is forced to a stop and the actual disposal code is just two lines; see Example 3.

Example 3: Destructor.

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

The class data is destroyed when the destructor calls the Free function. This is defined in the C_Classes header, and like the Allocate function, is a wrapper around the C library malloc/free heap memory management. Free decrements the internal counter that was incremented by Allocate.

The vtable class's destruction is handled by the DestroyVtable function that is also defined in the C_Classes header. While the constructor increments the class InstCount variable, it is decremented in DestroyVtable. The counter going to zero implies that this is the last instance of the class to be destroyed, and consequently, the vtable is deleted from RAM by a call to Free.

All functions in a class code file are declared as static—the only access is via the class pointer. Listings One and Two show the C_Classes header and code files. The Motor class header (plain.h) and code files (plain.c) are available for download here.

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 usage. 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;
}

The vtable Copy Macro

I try not to use macros very often, but for the vtable, copiers save typing a lot of fiddly and error-prone syntax. The definition in the C_Classes header is:

#define  CREATE_VTABLE(VECTOR, 
                    STRUCTURE, TYPEDEF) \
     VECTOR = (TYPEDEF*)Allocate
                    (sizeof(TYPEDEF)); \
            memcpy(VECTOR, &STRUCTURE,
                    sizeof(TYPEDEF))

It allocates space on the heap for the structure, assigning it to the VECTOR pointer, then copies the class vtable instance STRUCTURE from ROM to this space in the heap.

Data Hiding

At this point, C++ programmers are grumbling that I have exposed the class's data by publishing the MotorData structure in the header. This is true. There is nothing to stop users of this class typing a statement like:

newSpeed = MotorData->speed;

rather than calling the appropriate method, and so blowing away the very idea of objects. For example, what if the Motor class provided a revolutions-per-minute interface but internally used radians-per-second? To derive from a base class, it must somehow publish its data structure. However, an ordinary class need not. You simply move the data definition into the code file and replace all exposed references to the data structure with void pointers. From the examples so far, the SetSpeed definition in the header would then look like:

void (*SetSpeed)(void*, int);

and the example constructor, method call, and destructor would look like:

void* MotorData = MotorCtor();
Motor->SetSpeed(dMotor, 450);
MotorXtor(dMotor);

Externally, the data pointer is now useless, but within the code file, a simple macro is used to cast the void pointer. The source-code listings (available electronically) all include the ME macro for reference. Its use in the aforementioned SetSpeed method would be:

void SetSpeed(void* d,int speed)
{
  ME(d)->mSpeed = speed;
}

Of course, a little source-code sticky-nosing would allow any programmer to learn the class data structure, but I am assuming that those using these methods would not willfully bypass their intent, and using void pointers makes accidental use very unlikely. The downside is you lose the structure cross-checking capability of the compiler.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.