A typical way to do objects in C could be
Code:
struct dog_functions {
void (*bark)(struct dog* this);
void (*pee)(struct dog* this, struct firehydrant* target);
void* data;
};
struct dog {
struct dog_functions* fns;
int feet;
int age;
const char* name;
void* data;
}
So if you have a struct dog, *fido, you can say fido->fns->bark(fido); or fido->fns->pee(fido, my_firehydrant);
You can accomplish polymorphism by modifying the dog_functions struct attached to fido.
A real world example of this is the VFS in the linux kernel. I've tried to more or less follow its layout here.
The reason dog_functions is broken out into a separate struct is so you can save space by having multiple dogs point to the same dog_functions struct.
There's not a real great mechanism for inheritance here, I can show you one for single inheritance if you want -- there's a gobject library that does this. All the documentation for gobject, glib, and gtk will give you some idea of how OO works in C.
"Overloaded" C functions generally tend to look like void foo_int(int a), void foo_char(char c), void foo_double(double d), etc. i.e., they aren't overloaded functions : ) The varargs path is one of last resort, but it's there too.