Monday, November 19, 2007

Object Oriented Programming in C - Proof of Concept

Hi,
I believe that the title of this post will come as a surprise to quite a few people in India (I don't know what is the situation outside). The major reason being that probably none of the books in the market on C programming, reveals that this is possible. Now, most people follow the textbooks and rarely try to question what the author is trying to teach them. If the author castigates C for something and praises C++/Java (your OO supporting language here), it is taken for granted, without ever questioning if what the book says is really correct (I mean things the authors say are problems with C or cannot be done in C).

What I want to say is that there are a lot of biased programming texts in the market which do not the convey the true picture. C is their favourite scapegoat when they teach (?) object-oriented programming. Object-Oriented programming at its core is nothing more than a set of best practices, it is not a silver bullet. Any language that supports OO well is called object-oriented, C does not support it very well hence it is not called so. That does not mean you can't do it, it only requires true skill and solid knowledge of the concepts.

Now we will see how to construct the equivalent of class in C. Since class is the thing from where distinction starts between C and OO languages, this should be a convincing proof of concept. Let's put down the main (or you might say basic) features of the class construct and try to get the equivalent in C.
  • A class contains variables (state) and methods/member functions that operate on the state.
  • A class provides you with data encapsulation so that only those methods that need to access the state of class and change it are allowed to do so.
  • A class has constructor method(s) which allow for safe initialization.
  • A class has a destructor that allows for reclamation of memory when it is not to be used again.
For the demo, let us take a simple class that represents a stack. The stack is being implemented using an array.

class Stack {
char *symbols; // pointer to a character array containing the symbols (single chars) in the stack
int top; // top of stack index
int max_size; // maximum size
public:
Stack(int size); // constructor
~Stack( ); // destructor

void push(char symb);
char pop( );
};

Here's the C equivalent. However, I must first point out that much of the following has been taken from the ebook by Axel-Tobias Schreiner, ooc.pdf, from where I learned this. There a couple of pages that point out an altenative and less frightening method to use object-oriented techniques in C. I will be listing them soon.

Header File: new.h

/* methods for creating and destroying any object */
void *new (const void * type, ...);
void delete (void * item);

/* methods common to all objects */
void *clone (const void *self);
int differ (const void *self, const void *other);
size_t sizeOf (const void *self);

Header File: class.h

struct Class {
size_t size;
void * (* ctor) (void * self, va_list * app);
void * (* dtor) (void * self);
void * (* clone) (const void * self);
int (* differ) (const void * self, const void * b);
};

Header File: stack.h

extern const void *Stack; /* the ADT representation for Stack */

void push (void *, char);
char pop (void *);

Implementation of Stack: stack.c

#include "class.h"
#include "stack.h"

struct Stack {
const void *class; /* this should be the first member of the structure always */
/* can put data that is publicly accessible here */
};

/* Data Encapsulation provided by giving the following variables internal linkage in this file,
only functions in this file can access and modify these variables directly */
static char *symbols;
static int top;
static int max_size;

static void *Stack_ctor (void *_self, int size) { ... } /* the constructor function */
static void *Stack_dtor (void *_self) { ... } /* the destructor function */
static void *Stack_clone (const void *_self) { ... } /* this function completely copies one object to other */
static void *Stack_differ (const void *_self, const void *other) { ... } /* this function can check if two objects are the same */

/* initialize the generic Class structure with function pointers specific to the object */
static const struct Class _Stack = {
sizeof(struct Stack),
Stack_ctor,
Stack_dtor,
Stack_clone,
Stack_differ
};
const void *Stack = &( _Stack );

void push (struct Stack *, char symb) { ... }
char pop (struct Stack *) { ... }

User Code

#include "stack.h"
#include "new.h"

int main (void)
{
void *mystack = new (Stack, 20);
char popsymb;

push (mystack, 'X');
popsymb = pop (mystack);
delete(mystack);
return 0;
}

To keep it easier, I have divided this topic into more than one posts. The explanation of above C code comes in the next part of this topic.

No comments: