How can I simulate OO-style polymorphism in C?
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(...);
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.
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->pVTable->SomeFunction)(this, i);
}