Sol*_*lix 7 c java polymorphism vtable dynamic-dispatch
我希望在C中实现动态调度的提示(最好通过一个很好的例子).
我正在学习C并且作为练习,我想使用动态调度虚拟方法表从Java转换为C.
例如我有一个java代码:
abstract class Foo {
public abstract int val();
public abstract Boolean error();
}
class Fail extends Foo {
public int val(){ return 0;}
public Boolean error(){return true;}
}
class IntFoo extends Foo {
int v;
public IntFoo(int value){this.value=v;}
public int val(){ return v;}
public Boolean error(){return False;}
}
Run Code Online (Sandbox Code Playgroud)
我可以翻译一些像这样的基本内容:
typedef struct Foo{
void(**vtable);
}Foo;
typedef struct Fail{
void(**vtable);
struct Foo inherited;
}Fail;
typedef struct IntFoo{
void(**vtable);
struct Foo inherited;
}IntFoo;
Run Code Online (Sandbox Code Playgroud)
我在试图完成这个时遇到困难,因为我不知道:
vtable以便编译器识别正确的调用方法.没有简单的方法可以做到这一点.不过,您可以手动执行C++编译器正在执行的操作.在您的情况下,这将看起来像:
typedef struct vtable_Fail
{
int (*val)(struct Fail *this_pointer);
bool (*error)(struct Fail *this_pointer);
} vtable_Fail;
typedef struct vtable_IntFoo
{
int (*val)(struct IntFoo *this_pointer);
bool (*error)(struct IntFoo *this_pointer);
} vtable_IntFoo;
int Fail_val(struct Fail *this_pointer)
{
return 0;
}
...
void IntFoo_ctor(struct IntFoo *this_pointer, int value)
{
this_pointer->v = value;
}
int IntFoo_val(struct IntFoo *this_pointer)
{
return this_pointer->v;
}
...
struct Fail
{
vtable_Fail *vtable;
};
struct IntFoo
{
vtable_IntFoo *vtable;
int v;
};
Run Code Online (Sandbox Code Playgroud)
我们的想法是每个结构都应该有一个伴随的vtable结构,它存储指向该结构实现的所有虚方法的指针.Vtable结构每个只有一个实例.它们应该驻留在静态内存中,它们应该包含指向函数的指针.这些指针应该以每个特定结构所需的方式实现虚方法.结构本身可以有很多实例.实例中的Vtable数据文件应指向其类的静态vtable结构.
参数this_pointer传递实例的地址.它应该手动传递.这是一天结束时的C.
请注意,您需要分配vtable结构,init vtable指针等.您需要使用自己的代码手动完成所有这些操作.
我推荐的方法是查看其他一些使用调度表的 C 代码并了解其结构。我立即想到的具体示例(也许不是最好的教学示例,因为它们只是我开发过的随机自由软件)是 MIT Kerberos 和 Heimdal,它们都使用调度表地点和 Apache Web 服务器以及它如何处理动态加载的模块。这些都没有继承,但添加继承相对简单:您查看尝试调用的方法是否为 NULL,如果是,则检查该方法的父调度表。
一般来说,如何在 C 中处理调度表的简短版本是定义一个类似于 C++ vtable 的数据结构,它保存函数指针和某种确定要使用哪个指针的方法。就像是:
typedef void (*dispatch_func)(void *);
struct dispatch {
const char *command;
dispatch_func callback;
};
Run Code Online (Sandbox Code Playgroud)
是超通用版本,它将字符串方法名称映射到采用单个匿名指针作为参数的函数。您的实际调度表将是这些的数组,如下所示(取自 INN 源中的tinyleaf 的修改示例):
const struct dispatch commands[] = {
{ "help", command_help },
{ "ihave", command_ihave },
{ "quit", command_quit }
};
Run Code Online (Sandbox Code Playgroud)
显然,您对函数了解得越多,原型就越具体,并且可以将其他选择标准(例如参数数量)嵌入到调度表中。(实际的 INN 源具有最小和最大参数计数,传入参数结构而不仅仅是 void *,并在调度表中包含命令描述。)
搜索调度表的基本代码非常简单。假设您有一个由这些调度结构条目组成的数组vtable以及表的长度length,如下所示:
for (i = 0; i < length; i++)
if (strcmp(command, vtable[i].command) == 0) {
(*vtable[i].callback)(data);
return;
}
Run Code Online (Sandbox Code Playgroud)
要实现继承,您需要父指针,如果您脱离循环末尾,则向上移动到父指针并重复逻辑。(显然,这对于递归函数来说可能是一个有用的地方。)
| 归档时间: |
|
| 查看次数: |
1160 次 |
| 最近记录: |