In my experience in object oriented C programming I have seen two ways to implement derived classes.
First Method, have a definition of the parent class as a .h file. Then each class that derives from this class will have do:
File parent_class.h:
int member1;
int member2;
File testing.c:
struct parent_class {
#include "parent_class.h" // must be first in the struct
}
struct my_derived_class {
#include "parent_class.h" // must be first in the struct
int member3;
int member4;
}
Second Method, would do:
File testing.c:
struct parent_class {
int member3;
int member4;
}
struct my_derived_class {
struct parent_class; // must be first in the struct
int member3;
int member4;
}
What is your favorite method of doing derived classes in C ( doesn't have to be what I have done )? and why?
Which method would you prefer, first or second method ( or your own )?
The second way has the advantage of typesafety with inherited methods. If you want to have a method foo(struct parent_class bar) and call it with foo((struct parentclass) derived_class), this will work correctly. The C-Standard defines this. Thus, I'd generally prefer method #2. In general, it is guaranteed that casting a structure to its first member will result in a struct containing the data of the first member of the struct, no matter how memory is laid out.
I know that GNOME uses the 2nd method, and casting pointers was a known thing as well. I don't remember there being any real hoops to jump through to do so. In fact, From a C memory model standpoint, there can't be any semantic difference between the two, since AFAIK the only possible difference would be compiler differences in structure padding, but since the code all runs through the same compiler, that would be a moot point.
At a former job, we used a preprocessor to handle this. We declared classes using a simple C++-style syntax, and the preprocessor generated C headers that were basically equivalent to the First Method, but without the #includes. It also did cool things like generating vtables and macros for upcasting and downcasting.
Note that this was in the days before good C++ compilers existed for all the platforms we targeted. Now, doing this would be stupid.