C 编程/GObject
由于 C 编程语言不是为面向对象编程而创建的,因此它没有对类、继承、多态和其他面向对象概念的明确支持。它也没有自己的虚拟表,这在像 C++、Java 和 C# 这样的面向对象语言中被找到。因此,仅使用 C 的语言特性和标准库来实现面向对象编程范式可能并不容易。但是,可以通过使用包含函数指针和数据的结构,例如,或者使用第三方库来实现。
有很多第三方库旨在为 C 中的面向对象编程提供支持。其中最通用的也是最广泛使用的库是 GObject 系统,它是 Glib 的一部分。GObject 系统自带虚拟表。要使用 GObject 系统在 C 中创建一个对象,它必须从 GObject 结构体中进行子类化。
在这个例子中,一个新的对象将被直接实现,并从 GObject 派生。为了简单起见,该对象被命名为MyObject。
要创建一个简单的不可派生(最终)对象,必须声明两个结构体,实例和类。它们使用宏声明
/* in myobject.h */
G_DECLARE_FINAL_TYPE (MyObject, my_object, MY, OBJECT, GObject)
这声明了两个结构体,MyObject 和 MyObjectClass。MyObject 必须在 C 实现中定义,而 MyObjectClass 已经由宏定义了。
由于 GObject 系统只是一个第三方库,因此无法对 C 语言本身进行任何更改,创建新对象需要大量样板代码。这主要由上面显示的宏处理。但是,以下内容也是必需的
/* in myobject.h */
#define MY_TYPE_OBJECT my_object_get_type ()
该宏定义了几个函数,即 MY_OBJECT() 和 MY_OBJECT_CLASS(),用于强制转换,MY_IS_OBJECT() 和 MY_IS_OBJECT_CLASS() 用于测试对象或类是否为正确的类型,以及 MY_OBJECT_GET_CLASS() 用于从实例获取类结构。
在使用之前,必须定义新创建的对象,以及实例结构体。
/* in myobject.c */
struct _MyObject
{
GObject parent_instance;
/* other members */
};
G_DEFINE_TYPE (MyObject, my_object, G_TYPE_OBJECT)
有一些静态函数可能需要定义,也可能不需要定义,具体取决于您的对象。对于最小对象,这些函数是强制性的
/* in myobject.c */
static void
my_object_class_init (MyObjectClass *klass)
{
/* code */
}
static void
my_object_init (MyObject *self)
{
/* code */
}
在 C 中没有内部方法可以分配内存给对象。因此,必须为新对象声明一个显式构造函数。
/* in myobject.c */
GObject *
my_object_new (void)
{
return g_object_new (MY_TYPE_OBJECT,
0);
}
虽然使用对象自己的指针类型来创建对象是完全有效的,但建议使用层次结构顶部的对象的指针类型,即最远的基类。现在可以像这样使用新创建的对象
/* in main.c */
/* Note: GObject is at the top of the hierarchy. */
/* declaration and construction */
GObject *myobj = my_object_new ();
/* destruction */
g_object_unref (myobj);
继承是最广泛使用和最有用的面向对象概念之一。它通过将现有代码包装成一个对象,然后对其进行子类化,提供了一种有效的方法来重用现有代码。新的类被称为派生类。可以使用继承创建许多对象层次结构。继承也是抽象代码的最有效方法之一。
在 GObject 系统中,可以通过对GObject进行子类化来实现继承。由于 C 没有提供继承的关键字或运算符,因此派生对象通常是通过将基实例和基类分别声明为派生实例和派生类的成员来创建的。在 C 代码中
/* derived object instance */
struct _DerivedObject
{
/* the base instance is a member of the derived instance */
BaseObject parent_instance;
};
- Hanser. "用 ANSI-C 进行面向对象编程". 1994. Hanser 描述了在标准 ANSI C 中实现类、继承、实例、方法、对象、vtable、多态、后期绑定等的其他方法。
- Gregory Naçu - C64OS.com. "6502 中的面向对象(第二部分)". 2019. Greg Nacu 描述了在使用很少内存的6502 汇编语言中实现类、继承、实例、方法、对象等的其他方法。
- Greg Kroah-Hartman. "关于 kobject、kset 和 ktype 的所有内容". 镜像:"关于 kobject、kset 和 ktype 的所有内容". 2007.