Set*_*jmp 7 c inheritance object c99 c89
我特别感兴趣的是在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 */
};
Run Code Online (Sandbox Code Playgroud)
使用这些结构定义,实现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;
}
Run Code Online (Sandbox Code Playgroud)
然后,在使用foo的代码中:
struct foo *foop = new_foo(...);
foop->ops->blah(foop, ...);
foop->ops->plugh(foop, ...);
Run Code Online (Sandbox Code Playgroud)
此代码可以使用宏或内联函数进行整理,因此它看起来更像C
foo_blah(foop, ...);
foo_plugh(foop, ...);
Run Code Online (Sandbox Code Playgroud)
虽然如果你坚持使用一个相当短的名称"ops"字段,只需写出原来显示的代码并不是特别冗长.
这种技术完全适用于在C中实现相对简单的基于对象的设计,但它不能处理更高级的要求,例如显式表示类和方法继承.对于那些,你可能需要像GObject(如EFraim所提到的),但我建议确保你真的需要更复杂的框架的额外功能.
你对术语"对象"的使用有点模糊,所以我假设你在问如何使用C来实现面向对象编程的某些方面(在这个假设下随意纠正我.)
方法多态性:
方法多态性通常使用函数指针在C中进行模拟.例如,如果我有一个用于表示image_scaler的结构(需要一个图像并将其调整为新尺寸),我可以这样做:
struct image_scaler {
//member variables
int (*scale)(int, int, int*);
}
Run Code Online (Sandbox Code Playgroud)
然后,我可以制作几个图像缩放器:
struct image_scaler nn, bilinear;
nn->scale = &nearest_neighbor_scale;
bilinear->scale = &bilinear_scale;
Run Code Online (Sandbox Code Playgroud)
这让我可以为任何接受image_scaler的函数实现多态行为,并通过简单地传递一个不同的image_scaler来使用它的缩放方法.
遗产
通常通过以下方式实现继承:
struct base{
int x;
int y;
}
struct derived{
struct base;
int z;
}
Run Code Online (Sandbox Code Playgroud)
现在,我可以自由地使用派生的额外字段,以及获得所有"继承"的字段.此外,如果您有一个只接受结构基础的函数.你可以简单地将struct dervied指针转换为struct base指针而不会产生任何后果
诸如GObject之类的库。
基本上,GObject 提供了描述不透明值(整数、字符串)和对象的通用方法(通过手动描述接口 - 作为函数指针的结构,基本上对应于 C++ 中的 VTable) - 有关该结构的更多信息可以在其参考中找到
您还经常会手动实现 vtable,如“纯 C 中的 COM”中所示