5

Possible Duplicate:
Can you write object oriented code in C?

Hi!

Just for the fun of it, I've been experimenting these last two days with creating a very simple, very straightforward object environment in pure C. I've been toying around with macros, dynamic linking, type-description structures and the like, and I've arrived at the following:

string_o str = new(String, "hello world");
list_o list = new(List);

List.pushf(list, str);

printf("In the list: \"%s\"\n",
       String.text(List.popf(list)));

delete(list);
delete(str);

Looks and works kinda nice, but I can't figure a way to fake instance methods. I can't get past Class.function(instance), not without global macro replacements for function names, which defeats the purpose of encapsulation.

Again, this is an experiment, just for the challenge and the fun =). Can you guys help me figure out a way to do this? I don't want to use additional preprocessing, only plain C and GCC macros.

edit> forgot to say -- I don't want each instance to contain the function pointers in its structure. That would give me method syntax alright, but it would mean that a 4-byte data object would have a dozen function pointers copied over to each instance. That's kinda like cheating =P haha

Thanks in advance!

Community
  • 1
  • 1
salezica
  • 74,081
  • 25
  • 105
  • 166
  • 3
    isnt that why they created cpp? :P – Toby Nov 05 '10 at 05:03
  • 3
    Associate each 'class' with a table of function pointers that get executed when you call a 'member function'? – wkl Nov 05 '10 at 05:05
  • @Tobias: _shudder_, I hope not! [C++: an octopus made by nailing extra legs onto a dog.](http://en.wikiquote.org/wiki/Programming_languages#C.2FC.2B.2B) - Steve Taylor :P – Matt Ball Nov 05 '10 at 05:06
  • 4
    http://en.wikipedia.org/wiki/Objective-C – Alex Reynolds Nov 05 '10 at 05:06
  • There are several extend question on doing OO in c (an early example is [Can you write object oriented code in C?](http://stackoverflow.com/q/351733/2509)). You may want to implement a virtual function table for your classes. – dmckee --- ex-moderator kitten Nov 05 '10 at 05:06
  • check out Glib's GObject, library that provides some OO features in C. http://en.wikipedia.org/wiki/GObject – Roman Hwang Nov 05 '10 at 05:22
  • @birryee: I do exactly that, but that doesn't give me method syntax. @Tobias @Alex: good thing I said twice this was an experiment, for fun xD I am well aware of pre-existent object oriented languages and are not trying to home-bew one. @everyone else: thanks for the links! I'll check them! – salezica Nov 05 '10 at 05:29
  • Take a look at this answer http://stackoverflow.com/questions/3325306/should-i-learn-to-implement-oop-in-c-are-there-projects-that-use-oop-in-c/3325357#3325357 – Matt Joiner Nov 05 '10 at 05:50
  • 1
    Isn't "global macro replacements for function names" is what C++ name mangling essentially does? – Lie Ryan Nov 05 '10 at 06:27

1 Answers1

14

Object orientation in C is normally done with function pointers. That means a structure which contains not only the data for an instance but the functions to call as well.

It's the easiest way to do inheritance and polymorphism in C. By way of example, here's an object-orientd communications example.

It only has one method open but you can see how that differs for the TCP and HTML sub-classes. By having an initialisation routine which sets the a class-specific function, you get polymorphism.

#include <stdio.h>

// The top-level class.

typedef struct _tCommClass {
    int (*open)(struct _tCommClass *self, char *fspec);
} tCommClass;

// Function for the TCP class.

static int tcpOpen (tCommClass *tcp, char *fspec) {
    printf ("Opening TCP: %s\n", fspec);
    return 0;
}
static int tcpInit (tCommClass *tcp) {
    tcp->open = &tcpOpen;
    return 0;
}

// Function for the HTML class.

static int htmlOpen (tCommClass *html, char *fspec) {
    printf ("Opening HTML: %s\n", fspec);
    return 0;
}
static int htmlInit (tCommClass *html) {
    html->open = &htmlOpen;
    return 0;
}

// Test program.

int main (void) {
    int status;
    tCommClass commTcp, commHtml;

    // Same base class but initialized to different sub-classes.
    tcpInit (&commTcp);
    htmlInit (&commHtml);

    // Called in exactly the same manner.

    status = (commTcp.open)(&commTcp, "bigiron.box.com:5000");
    status = (commHtml.open)(&commHtml, "http://www.microsoft.com");

    return 0;
}

A more complete answer can be found here.

In response to your comment:

I don't want the functions contained in every single instance.

You're probably right. It's unnecessary to duplicate that information when it will be the same for every instance of a single class.

There's a simple way around that. Rather than having every instance carry its own set of function pointers, you create one structure holding them for the class, then each instance gets a pointer to that structure.

That will save quite a bit of space at the (minimal) cost of having to do two levels of indirection to call a function.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Thanks for the answer, but I forgot to say, I don't want the functions contained in every single instance. Imagine if each list node, or wrapped integer, or whatever, had to contain 20 function pointers! – salezica Nov 05 '10 at 05:25
  • 1
    Well, then you could have a _single_ pointer in the structure which pointed to a class-specific array of function pointers. You would have to use double indirection to call the functions rather than single indirection, but it would save you the space. I'll add that to my answer. – paxdiablo Nov 05 '10 at 05:29
  • Sorry, I just read that! Yeah, I'm not worried about being *unable* to reach the functions. I could do (suppose a pointer to the class in the object is called 'f') object->f->fun(object); but it looks ugly as hell hahah. I'm trying to macro my way up to object.fun(); -- don't know if it's possible at all though. – salezica Nov 05 '10 at 17:02