views:

1202

answers:

9

Is there a way to write OO-like code in the C programming language?


See also:

Found by searching on "[c] oo".

+2  A: 

Check this article out to achieve function polymorphism:

http://thewizardstower.org/thelibrary/programming/polyc.html

Jonas Gulle
+14  A: 

Common approach is to define struct with pointers to functions. This defines 'methods' which can be called on any type. Subtypes then set their own functions in this common structure, and return it.

For example, in linux kernel, there is struct:

struct inode_operations {
    int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
    struct dentry * (*lookup) (struct inode *,struct dentry *, 
                               struct nameidata *);
    ...
};

Each registered type of filesystem then registers its own functions for create, lookup, and remaining functions. Rest of code can than use generic inode_operations:

struct inode_operations   *i_op;
i_op -> create(...);
Peter Štibraný
That's basically how cfront (the original C++ compiler) converted C++ to C that was then compiled with pcc. I learned a lot about how this worked dealing with core files from that mess.
Paul Tomblin
Sounds like fun :-)
Peter Štibraný
+7  A: 

The first C++ compiler ("C with classes") would actually generate C code, so that's definitely doable.

Basically, your base class is a struct; derived structs must include the base struct at the first position, so that a pointer to the "derived" struct will also be a valid pointer to the base struct.

typedef struct {
   data member_x;
} base;

typedef struct {
   struct base;
   data member_y;
} derived;

void function_on_base(struct base * a); // here I can pass both pointers to derived and to base

void function_on_derived(struct derived * b); // here I must pass a pointer to the derived class

The functions can be part of the structure as function pointers, so that a syntax like p->call(p) becomes possible, but you still have to explicitly pass a pointer to the struct to the function itself.

UncleZeiv
+2  A: 

C++ is not that far from C.

Classes are structures with a hidden pointer to a table of function pointers called VTable. The Vtable itself is static. When types point to Vtables with the same structure but where pointers point to other implementation, you get polymorphism.

It is recommended to encapsulate the calls logic in function that take the struct as parameter to avoid code clutter.

You should also encapsulcte structures instantiation and initialisation in functions (this is equivalent to a C++ constructor) and deletion (destructor in C++). These are good practice anyway.

typedef struct
{
   int (*SomeFunction)(TheClass* this, int i);
   void (*OtherFunction)(TheClass* this, char* c);
} VTable;

typedef struct
{
   VTable* pVTable;
   int member;

} TheClass;

To call the method:

int CallSomeFunction(TheClass* this, int i)
{
  (this->SomeFunction)(this, i);
}
Think Before Coding
A: 

The file functions fopen, fclose, fread are examples of OO code in C. Instead of the private data in class, they work on the FILE structure which is used to encapsulate the data and the C functions acts as an member class functions. http://www.amazon.com/File-Structures-Object-Oriented-Approach-C/dp/0201874016

Priyank Bolia
The title reads now: `An Object-Oriented Approach with C++`
prinzdezibel
+1  A: 

The cool way is to write your code in SIMULA :)

No, just kidding, but check this out...

It's one of the first languages with classes (and the main inspiration for C++).

This compiler will generate C code for it, and compile directly to machine code. I just created this set of classes with an abstract class A.

Begin
Class A;
   Virtual: Procedure print Is Procedure print;;
Begin
End;

A Class B (c);
   Character c;
Begin
   Procedure print;
     OutChar(c);
End;

B Class C;
Begin
   Procedure print;
     OutChar(c);
     OutChar(c);
End;


! Main program;
Ref (A) rb;
Ref (C) rc;

rb :- New B ('B');
rb.print;
rc :- New C ('C');
rc.print;
End;

cim -t cim_test.cim and you get:

./cim_test

BCC

The -t switch will let you explore *cim_test.c* but it is NOT pretty, and definitely not "editable".

Andrei Taranchenko
A: 

The GObject library is a world-class example of implementing a polymorphic object model in C.

Pete Kirkham
A: 

Appendix B of the article Open Reusable Object Models, by Ian Piumarta and Alessandro Warth of VPRI is an implementation of an Object model in C, in a few lines of code. It's a fascinating read !

Here's the uncached version of the macro that sends messages to objects:

typedef struct object *oop; 
typedef oop *(*method_t)(oop receiver, ...);

//...

# define send(RCV, MSG, ARGS...) ({ \ 
    oop r = (oop)(RCV); \ 
    method_t method = _bind(r, (MSG)); \ 
    method(r, ##ARGS); \ 
})
Sébastien RoccaSerra
A: 

What about that language called Objective-C that accomplishes this rather elegantly?

Genericrich
You may as well say what about C++, anyway he may not be using an Apple
johnc
Objective C is not C, so offering it as a suggestion for how to do anything in C is not worthwhile.
Tom
Objective-C is slim superset of C, so anything you can write in C will compile and run in Objective-C.
Genericrich
Also, you don't need a Mac to run Objective-C. You can't (afaik) run it on a Microsoft OS though.
Genericrich
Does Objective-C incorporate C99 features? C++ used to be a superset of C, but C99 changed that.
Tom
@Tom: As I understand it, it does. Objective-C is a STRICT superset of C, so any C program can be compiled and run.
Genericrich