C-Scene Issues 1..9 Authors
Algorithms Books Patterns Graphics Miscellaneous UNIX Web & XML Windows
Feedback FAQs Changes Submissions

OOP in C

by YOUR NAME
last updated 2001/08/07 (version 1.1)
also available as XML

NoteThis article is work in progress and not yet finished!

It is possible to write object oriented programs in plain C. This is often uglier, and more dangerous than doing it in an object oriented langauge but you can do it.

There are several methods which can be used.

Firstly if we are dealing with a prototype style oop then we don't need to worry about classes, and we can use C's file-level encapsulation to restrict the interface.

For example, if we have an accessor object whose interface is the methods Open, Close, Read and Write, but has the internal methods Foo, Zog, and Harry, then we could implement it like this

accessor.h

int Open(char *name):
int Close(int handle):
int Read(int handle, char *buf, int len):
int Write(int handle, char *buf, int len):

mymodule.c { ... } is elided code

int Open(int handle, char *name) { ... }
int Close(int handle) { ... }
int Read(int handle, char *buf, int len) { ... }
int Write(int handle, char *buf, int len) { ... }
static int Foo() { ... }
static int Zog(int x) { ... }
static int Harry(char *x, int l) { ... }

So we use the static keyword to prevent external access to a symbol.

This may not appear terribly useful at first, but consider where you are writing a module to be dynamically loaded into a server, this is case where the module needs to conform to an Interface, and is essentially an object.

Multiple instances may be referenced by passing a handle to the interface, and the allocation/deallocation can be handled internally to the class.

A more usual form of OOP in C can be achieved by using structures and function pointers. We can even implement a form of inheritance by overlapping structures.

int drawWidget(struct widget *w);       /* not virtual */

typedef struct widget {
	char *name;
	int x, y;
} widget; 

typedef struct callbackWidget {
	struct widget tag;
	int (*callback)(struct callbackWidget *w);       /* virtual */
	int cbValue;
} callbackWidget; 

typedef struct pressWidget {
	struct callbackWidget tag;
	int (*press)(struct pressWidget *w, int x, int y); /* virtual */
} pressWidget; 

int drawWidget(struct widget *w)
{
	printf("I drew da widget.\n");
}
void foo(pressWidget *x)
{
	drawWidget((widget *)x);
	x->press(x, 0, 0);
}
int pressWidgetPress(pressWidget *w, int x, int y)
{
	printf("Hey, I got pressed.\n");
}
main()
{
	pressWidget a;
	a.press = pressWidgetPress; 
	foo(&a);
}

drawWidget() is a non virtual method, and press is a virtual method.

With this method we're pretty much limited to what C++ can do, but we don't get the typing benefits, or the syntactical sugar.

There is one last form that I'm going to touch on today, and that is the use of a function as an encapsulating form, with objects referenced by opaque handles.

We can define a function as being the interface to an object, so essentially it is an class. Unfortuantely this limits us to a single actual interface so we'll probably need to use tuples to effectively communicate.

void Button(int handle, tuple *in, tuple **out)
{
	static button *buttons[10];     /* dodgey 10 buttons max implementation */

	if (buttons[handle] == NULL || handle < 0 || handle > 9) {
		*out = NULL;
		return;
	}  
	switch(in[0]) {
		case NEW: ...
			break;
		case DRAW: ...
			break;
	}
	return;
}
Note Here the tuples are probably just int arrays.

I haven't actually used this last method, and it appears to be rather clumsy and prone to needing too much typing, but it does give solid encapsulation. Inheritance can be implemented by chaining 'bits' of objects as objects, and then calling superclasses with the handle to the super-object and the appropriate tuples.

Ie, I have a pictureButton() class, this inherits the button() class. When I create an instance of the pictureButton class, it creates an instance of the button class, stores the handle in the instance of the pictureButton class that it creates, and then returns the handle to the pictureButton class.

Then when I ask the pictureButton to draw, it calls button with the button handle it has, with draw to draw the frame, etc, and then draws the picture inside the frame itself, using the information in its pictureButton interface.

I don't realistically recommend this last method for any solution.

Having said this, OOP in C is often undesirable, often it is better served by structured code and a modular design, but the concepts that OOP pushes do fit quite well into modular/structured design, encapsulation, polymorphism being the most usable features, with inheritance being somewhat less usable (except where it fits in with polymorphism).

If you want to do OOP in C for itself I would recommend Objective C, or C++. If you want to do C, but use some OOP principles, then these techniques may be of some interest.

This article is Copyright © 2000 by C-Scene. All Rights Reserved.


Copyright © 1997-2000 by C-Scene. All Rights Reserved.

Part of the graphics and stylesheets used to generate this site are
Copyright © 1999-2000 by Apache Software Foundation.