你们会用这种方式在 C 中创建“类”吗?那么接口呢?我猜我们只是对所有东西都使用函数指针,并且可以更改函数指针指向的位置?
#ifndef CLASS
#define CLASS
void method1() { printf("method #1"); }
void method2() { printf("method #2"); }
typedef struct {
void (*method1)(void);
void (*method2)(void);
} Class;
Class class;
void class_setup()
{
class.method1 = &method1;
class.method2 = &method2;
}
#endif
int main()
{
class_setup();
class.method1();
class.method2();
return 0;
}
this
实际上,在 C 语言中有两种实现 OOP 的方法。虽然函数指针在其中确实发挥了重要作用,但我们并没有将它们放在“类”结构中 - 主要是因为在 C 语言中我们没有它们。类作为一组开放的函数
这是一种最常见的方法,虽然不是很漂亮,但仍然可用。只需使用一堆函数来对对象执行某些操作即可。例如,请查看Glib和GTK+。这两个库实际上是 C 中最常用和最易用的面向对象库。对于 GTK+,要使用“兄弟”类,请使用“兄弟”函数:
如您所见,您需要将一个指针传递给对象(
this
)作为第一个参数,并通过函数名称区分此方法属于哪个类。同时,两个类(GtkWindow
和GtkButton
)都是的子类GtkWidget
,可以通过手动类型转换直接传递给gtk_widget_*()
函数:实际上,早期的 C++ 编译器只是使用相同方法生成 C 代码的预处理器。方法
cls::foo()
变成了函数cls_foo(cls *this)
。即使现在,如果你将 C++ 代码编译到共享库中,你也会看到里面只有一堆名称像这样的函数。阅读有关“名称改编”以及不同编译器如何进行名称改编的内容。类作为隐藏哈希表中的一组函数
这种实现 OOP 的方法很少使用。在商业产品中,它是在Photon中实现的- 旧 QNX 的 GUI 库(较新版本的操作系统已切换到 C++ 的 GUI)。开源项目示例:IUP
它使用不同的方法来处理方法 - 函数指针的哈希数组。创建新类时,需要在类列表中注册其唯一类型并注册所有方法。此外,没有父子数据类型,只有对象内部带有类标识符的基本数据类型。内部不太容易,但这为实际应用提供了一种更方便的方法:
在后台,该
PtSetResource()
函数将使用一个二维哈希表,该表的函数指针以类引用(PtWindow
或PtButton
从对象内部读取)和Pt_ARG_TEXT_STRING
直接传递给函数的方法选择器()为键。为了在 C 中创建“类”,您可以使用函数指针,它看起来像这样:
typedef void (*classMethod)(void);
请注意,此处的类型是“classMethod”,并且函数名称不必匹配。因此,要使用它,它看起来像
现在您已经拥有正确的方法,您需要在 class_setup 函数中设置它们。在 c 中,函数名称可以有效地被视为该函数的地址,因此这里不需要使用 &。它可以是
class.method1 = method1
(但是您仍然可以说 &method1,如果这对您来说更清楚,编译器会使用它)如果您需要使用与“self”或“this”等价的变量,则需要传递变量的地址,因为 C 没有任何内置方法来执行此操作。可以使用类似的函数指针来完成
typedef void (*classMethodSelf)(Class *);
。这将定义为您将看到类的 typedef 已被移动,这是因为需要在定义类型之前声明类型,以便将其
Class
作为类型传递给函数指针。如果您不熟悉指向结构的指针,则需要注意的另一件重要事情是,它的成员将通过variable->member
而不是来访问variable.member
。请注意,函数指针中的其他参数就像普通函数声明一样声明,但没有变量名。如果您希望该方法有一个返回值,只需更改 typedef 中的第一个类型即可。然后您可以像普通函数一样使用它。如果您有任何疑问或需要澄清,请询问,祝您有美好的一天。
不。在 C 中我们不这么做。C 没有类也没有方法。
我们有函数来做某事
我们有存储一些数据的结构
我们使用函数处理数据
我们也可以使用指向函数的指针来提供一些回调