我特别关注于在C语言内部使用的对象,而不是像Python这样的解释型语言的核心对象实现。
我特别关注于在C语言内部使用的对象,而不是像Python这样的解释型语言的核心对象实现。
我通常会像这样做:
struct foo_ops {
void (*blah)(struct foo *, ...);
void (*plugh)(struct foo *, ...);
};
struct foo {
struct foo_ops *ops;
/* data fields for foo go here */
};
有了这些结构定义,实现foo函数的代码看起来像这样:
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;
}
然后,在使用foo的代码中:
struct foo *foop = new_foo(...);
foop->ops->blah(foop, ...);
foop->ops->plugh(foop, ...);
这段代码可以通过宏或内联函数来优化,使其看起来更像C语言。
foo_blah(foop, ...);
foo_plugh(foop, ...);
struct image_scaler {
//member variables
int (*scale)(int, int, int*);
}
然后,我可以制作几个如下的图像缩放器:
struct image_scaler nn, bilinear;
nn->scale = &nearest_neighbor_scale;
bilinear->scale = &bilinear_scale;
struct base{
int x;
int y;
}
struct derived{
struct base;
int z;
}
现在,我可以自由使用派生类的额外字段,并获取基类的所有“继承”字段。此外,如果您有一个仅接受结构体基类的函数,您可以将您的结构体派生指针简单地转换为没有任何后果的结构体基类指针。
类库例如GObject。
基本上,GObject提供了一种通用的描述不透明值(整数、字符串)和对象(手动描述接口 - 作为函数指针结构,基本上对应于C++中的VTable - 更多关于该结构的信息可以在其参考文献中找到)的方式。
你经常也会像"COM in plain C"中那样手动实现vtables。
从浏览所有答案可以看出,有库、函数指针、继承、封装等等可用的方法(C++最初是C的前端)。
然而,我发现软件中非常重要的一个方面是可读性。你试过读10年前的代码吗?因此,在使用C中做对象等事情时,我倾向于采取最简单的方法。
问以下问题:
我通常会回到像GLIB API这样的东西,它允许我封装我的代码并提供非常易读的接口。如果需要更多,我会添加函数指针以进行多态。
class_A.h:
typedef struct _class_A {...} Class_A;
Class_A* Class_A_new();
void Class_A_empty();
...
#include "class_A.h"
Class_A* my_instance;
my_instance = Class_A_new();
my_instance->Class_A_empty(); // can override using function pointers
Node
和Expr
结构,例如:typedef struct {
NodeTag n;
} Node;
其中NodeTag
是无符号整数的typedef,有一个头文件,其中包含描述所有可能节点类型的一堆常量。节点本身看起来像这样:
typedef struct {
NodeTag n = FOO_NODE;
/* other members go here */
} FooNode;
一个 FooNode
可以毫不顾虑地转换为一个 Node
,因为 C 结构的一个怪癖:如果两个结构体具有相同的第一个成员,则它们可以互相转换。
是的,这意味着一个 FooNode
可以转换为一个 BarNode
,这可能不是你想要的。如果你想要正确的运行时类型检查,GObject 是一种好的选择,尽管在掌握它的过程中要准备好讨厌生活。
(注意:这些例子是从记忆中得出的,我已经有一段时间没有对 Postgres 内部进行过修改了。开发者常见问题解答 中有更多信息。)