Phil's guide to object-oriented ANSI C

I learned this technique in "Programming 101" in college.
(yes, that was almost literally the name of the course :-)]

The concept here is that you can program in "Object Oriented" style... even using venerable old ANSI C, a language not particularly valued for OO programming!

I have to preface by saying that this does not LOOK like object-oriented programming, for those people coming from a java or C++ background. But if you think about it with an open mind, it is.

The code section below demonstrates "instantiating" a new object. It then shows code performing "member functions" on the object, and finally, a clean deletion of the object.
In a following page, class Inheritence is introduced into the mix.

blah.c


#include "FooOBJ.h"

void diddle(FooOBJ obj){
	/* Perform member functions on FooOBJ.
	 * If you try these functions on a different type of object,
	 * you will get a compile-time error
	 */
	setFooNumber(obj, 1);
	setFooString(obj, "somestring");

}

int main(){
	FooOBJ fobj;
	fobj=newFooOBJ(); /* create a new object of type "FooOBJ" */

	dumpFooState(fobj);
	puts("Tweaking object");
	diddle(fobj);

	dumpFooState(fobj);
	deleteFooOBJ(fobj);

	return 0;
}


So there you have it; Complete object opacity, PLUS type safety. The caller will not be able to accidentally pass in a non FooOBJ, because of the typedef in the hidden header file(shown below).

This methodology has BETTER object abstraction than C++.
Why? Because callers have **NO IDEA** what the private members really are, and how they are implemented.

With C++, looking at the required header file usually tells you a great deal about the internal structure of the class, and allows you to "cheat". If you want to write your own header file in C++ overruling the "public" vs "protected" definitions, etc, there is nothing to stop you from doing easily so. Whereas in this methodology, you cannot do this, because the data structures are completely opaque. You can ONLY interact with the object through provided "member functions", which may be implemented in a binary .o file. You would have to spend some cosy time with a debugger to manage any tweaking of the object type involved.

FooOBJ.h consists of the following:

FooOBJ.h


typedef struct fooobj * FooOBJ;
FooOBJ newFooOBJ();
void setFooNumber(FooOBJ,int);
void setFooString(FooOBJ,char *); /* make comments about copy or not here */
void dumpFooState(FooOBJ);      /* dumps debug contents of FooOBJ to stdout */
void deleteFooOBJ(FooOBJ);


You simply cannot get better data hiding than that.

And just to spell things out and give you something to play with, here's a sample implementation of FooOBJ.o Note that there are quite a few different possibilities for it, and it doesnt matter to the "blah.c" code above. All that it needs is a FooOBJ.o file to link against.

Which is what object oriented programming is all about!

FooOBJ.c


#include <stdio.h>
#include "FooOBJ.h"

struct fooobj {
	int privateint;
	char *privateString;
	/* Depending on your preferences, you
	 * may prefer privateString to be a char buffer[],
	 * OR malloc it and free on delete.
	 */
};

/* Any "class static" vars simply get declared as
static int staticvar;
 * or whatever you like here.
 * Whereas instance variables go in the struct above.
 */

FooOBJ newFooOBJ(){
	FooOBJ foo=(FooOBJ)malloc(sizeof(struct fooobj));
	bzero(foo, sizeof(struct fooobj));
	return foo;
}

void setFooNumber(FooOBJ foo,int num){
	if(foo==NULL) return;  /* you may chose to debugprint something
				*instead
				*/
	foo->privateint=num;
}

void setFooString(FooOBJ foo,char *string){
	/* If you malloced the string, you'll want to free() it here!!*/
	if(foo==NULL) return;
	foo->privateString=string;
}
	

void dumpFooState(FooOBJ foo){
	if(foo==NULL) return;
	printf("value of private int==%d\n", foo->privateint);
        printf("value of private string==");
        if(foo->privateString == NULL){
		puts("(NULL)");
	} else {
		printf("%s\n", foo->privateString);
	}

}

void deleteFooOBJ(FooOBJ foo){
	/* dont forget to free privateString if you malloced it here!!*/
	free(foo);
}

Compiling hint

If you are unfamiliar with C compiling, you will probably want to compile the above files in the following manner:
cc -c *.c
cc -o foo *.o
Then if you want to play with the implementation of the "FooOBJ" object, you can change just the implementation part with:
cc -c FooOBJ.c
cc -o foo *.o

Inheritance

To learn about Object Inheritance, go to part 2


Author: phil@bolthole.com
Part of bolthole.com... ksh tutorial ... AWK Programming tutorial