I am especially interested in objects meant to be used from within C, as opposed to implementations of objects that form the core of interpreted languages such as python.
views:
511answers:
7Libraries such as GObject.
Basically GObject provides common way to describe opaque values (integers, strings) and objects (by manually describing the interface - as a structure of function pointers, basically correspoinding to a VTable in C++) - more info on the structure can be found in its reference
You would often also hand-implement vtables as in "COM in plain C"
I tend to do something like this:
struct foo_ops {
void (*blah)(struct foo *, ...);
void (*plugh)(struct foo *, ...);
};
struct foo {
struct foo_ops *ops;
/* data fields for foo go here */
};
With these structure definitions, the code implementing foo looks something like this:
static void plugh(struct foo *, ...) { ... }
static void blah(struct foo *, ...) { ... }
static struct foo_ops foo_ops = { blah, plugh };
struct foo *new_foo(...) {
struct foo *foop = malloc(sizeof(*foop));
foop->ops = &foo_ops;
/* fill in rest of *foop */
return foop;
}
Then, in code that uses foo:
struct foo *foop = new_foo(...);
foop->ops->blah(foop, ...);
foop->ops->plugh(foop, ...);
This code can be tidied up with macros or inline functions so it looks more C-like
foo_blah(foop, ...);
foo_plugh(foop, ...);
although if you stick with a reasonably short name for the "ops" field, simply writing out the code shown originally isn't particularly verbose.
This technique is entirely adequate for implementing a relatively simple object-based designs in C, but it does not handle more advanced requirements such as explicitly representing classes, and method inheritance. For those, you might need something like GObject (as EFraim mentioned), but I'd suggest making sure you really need the extra features of the more complex frameworks.
Your use of the term "objects" is a bit vague, so I'm going to assume you're asking how to use C to achieve certain aspects of Object-Oriented Programming (feel free to correct me on this assumption.)
Method Polymorphism:
Method polymorphism is typically emulated in C using function pointers. For example if I had a struct that I used to represent an image_scaler ( something that takes an image and resizes it to new dimensions ), I could do something like this:
struct image_scaler {
//member variables
int (*scale)(int, int, int*);
}
Then, I could make several image scalers as such:
struct image_scaler nn, bilinear;
nn->scale = &nearest_neighbor_scale;
bilinear->scale = &bilinear_scale;
This lets me achieve polymorphic behavior for any function that takes in a image_scaler and uses it's scale method by simply passing it a different image_scaler.
Inheritance
Inheritance is usually achieved as such:
struct base{
int x;
int y;
}
struct derived{
struct base;
int z;
}
Now, I'm free to use derived's extra fields, along with getting all the 'inherited' fields of base. Additionally, If you have a function that only takes in a struct base. you can simply cast your struct dervied pointer into a struct base pointer with no consequences
Similar to Dale's approach but a bit more of a footgun is how PostgreSQL represents parse tree nodes, expression types, and the like internally. There are default Node
and Expr
structs, along the lines of
typedef struct {
NodeTag n;
} Node;
where NodeTag
is a typedef for unsigned int, and there's a header file with a bunch of constants describing all the possible node types. Nodes themselves look like this:
typedef struct {
NodeTag n = FOO_NODE;
/* other members go here */
} FooNode;
and a FooNode
can be cast to a Node
with impunity, because of a quirk of C structs: if two structs have identical first members, they can be cast to each other.
Yes, this means that a FooNode
can be cast to a BarNode
, which you probably don't want to do. If you want proper runtime type-checking, GObject is the way to go, though be prepared to hate life while you're getting the hang of it.
(note: examples from memory, I haven't hacked on the Postgres internals in a while. The developer FAQ has more info.)
You may be interested in checking out the answers to my SO question.