This is fine and is a fairly common technique for implementing "object-orientation" in C. Because the memory layout of struct
s is well-defined in C, as long as the two object share the same layout then you can safely cast pointers between them. That is, the offset of the type
member is the same in the object
struct as it is in the cons_object
struct.
In this case, the type
member tells the API whether the object
is a cons_object
or foo_object
or some other kind of object, so you might be see something like this:
void traverse(object *obj)
{
if (obj->type == CONS) {
cons_object *cons = (cons_object *)obj;
traverse(cons->car);
traverse(cons->cdr);
} else if (obj->type == FOO) {
foo_object *foo = (foo_object *)obj;
traverse_foo(foo);
} else ... etc
}
More commonly, I've seem implementations where the "parent" class is defined as the first member of the "child" class, like so:
typedef struct {
enum type type;
} object;
typedef struct {
object parent;
object *car;
object *cdr;
} cons_object;
This works in largely the same way, except you've got a strong gaurantee that the memory layout of the child "classes" will be the same as the parents. That is, if you add a member to the 'base' object
, it'll automatically be picked up by the children and you won't have to manually make sure all of the structures are in sync.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…