I discovered this gem a few years ago. There's a way you can do struct inheritance in C.
But, the catch is, you'll just hide important data from the public. The data will still be there. If you plan, for example, to hide a dynamically allocated string, and the client attempts to free the pointer you provide on its own, it'll not free the hidden string. Yes, this can turn into memory leaks. Or worse, just reading garbage, if you typecast wrong children into the parent, then a function, which doesn't know anything about this context takes parent, and typecasts it into the expected type. It like, you're providing a Dog to a function that expects an Animal, and internally it converts to a Fish, because it expected a Fish, but it couldn't say so. It sounds crazy, but it leads to reading garbage, and to unexpected behaviors on the code.
So, use this at your own care.
One way I do it to prevent wrong typecasting (A->parent->B or Dog->Animal->Fish), is to use an enum variable within the parent struct, to tell the target functions about your intentions, as the c compiler will not complain about it. Also, one way of avoiding memory leaks is to make your own allocator/constructors and destructors, and ensure the client to use them. The client, in my pov, is anyone that is using the definitions listed in the header file.
main.c
#include <stdio.h>
#include <stdlib.h>
#include "hello.h"
// gcc -o app.exe main.c hello.c
int main(void) {
Hello *hi;
// This is what the public sees:
printf("Size of hello: %u\n", sizeof(Hello));
hi = hello_new();
printf("World says %i\n", hi->world());
hello_free(hi);
return 0;
}
hello.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
// This is what the public needs to see
typedef struct Hello {
int (*world)(void);
} Hello;
Hello *hello_new();
void hello_free(Hello *h);
hello.c
#include "hello.h"
// This is what the source code can see.
typedef struct HelloInternal {
Hello hello;
int foo;
int bar;
int other;
int fields;
int many;
int private;
int only;
int in_source_file;
} HelloInternal;
int hello_world() {
return 42;
}
Hello *hello_new() {
HelloInternal *hi = malloc(sizeof(HelloInternal));
hi->hello.world = hello_world;
hi->foo = 0;
hi->bar = 1;
hi->other = 2;
hi->fields = 3;
hi->many = 4;
hi->private = 5;
hi->only = 6;
hi->in_source_file = 7;
// Typecast to hide internal data
return (Hello *) hi;
}
void hello_free(Hello *h) {
free(h);
}
struct "Hello" has no field "foo"? GCC is sayingerror: redefinition of struct or union 'struct Hello'struct "Hello" has no field "foo", I'm stilling writing code without compiling in VSCode.