In a series of articles, Dan Saks introduces a possible implementation of virtual functions in C. Relying more on static type-checking, this is a different approach as opposed to the solution of A.-T. Schreiner with void *
pointers and dynamic type-checking.
Here is a stripped-down example without the vptr
s and vtable
s of Saks' version (for the sake of simplicity, function pointers are just members of struct Base
and struct Derived
).
#include <stdlib.h>
#include <stdio.h>
typedef struct Base Base;
// Base "class"
struct Base {
int (*get_param)(Base const *self);
};
inline int Base_get_param(Base const *self)
{
return self->get_param(self);
}
typedef struct Derived Derived;
// Derived "class"
struct Derived {
int (*get_param)(Derived const *self);
int param;
};
Derived * Derived_new(int param)
{
Derived *self = malloc(sizeof(Derived));
if (!self) abort();
self->get_param = Derived_get_param;
self->param = param;
return self;
}
void Derived_delete(Derived *self)
{
free(self);
}
inline int Derived_get_param(Derived const *self)
{
return self->param;
}
int main()
{
Derived *d = Derived_new(5);
printf("%d\n", Derived_get_param(d));
printf("%d\n", Base_get_param((Base *) d)); // <== undefined behavior?
Derived_delete(d);
return 0;
}
The gist is the function call (and cast) Base_get_param((Base *) d)
. Does this mean that the function pointer int (*get_param)(Derived const *self)
gets "implicitly cast" to int (*get_param)(Base const *self)
? Am I exploiting undefined behavior here (according to the C99 and C11 standards) because of incompatible types?
I get the proper output both with GCC 4.8 and clang 3.4. Is there a situation where the above implementation might be broken?
There is a detailed answer here about function pointer casts and compatible types but I am not sure about this case.