Java 用虚方法表实现C语言中的动态调度

Java 用虚方法表实现C语言中的动态调度,java,c,polymorphism,vtable,dynamic-dispatch,Java,C,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 Boole

我希望找到一个在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;}
}
我可以翻译一些基本的东西,比如:

typedef struct Foo{
    void(**vtable);
}Foo;

typedef struct Fail{
    void(**vtable);
    struct Foo inherited;
}Fail;

typedef struct IntFoo{
    void(**vtable);
    struct Foo inherited;
}IntFoo;
我在尝试完成此任务时遇到了困难,因为我不知道:

  • 如何在c中定义这些方法
  • vtable
    中设置这些方法的地址,以便编译器 识别要调用的正确方法
  • 还需要定义什么才能使其工作

  • 我推荐的方法是查看其他一些使用分派表的C代码,看看它是如何构造的。我头脑中所知道的具体示例(可能不是最好的教学示例,因为它们只是我所研究过的随机自由软件)是MIT Kerberos和Heimdal,它们都使用分布表和Apache web服务器以及如何处理动态加载的模块。这些函数都不执行继承,但继承的添加相对简单:您可以查看您试图调用的方法是否为NULL,如果是,则检查该方法的父分派表

    一般来说,如何处理C中的调度表的简短版本是,定义一个类似于C++ Vtable的数据结构,它包含函数指针和一些方法来确定使用哪一个指针。比如:

    typedef void (*dispatch_func)(void *);
    struct dispatch {
        const char *command;
        dispatch_func callback;
    };
    
    for (i = 0; i < length; i++)
        if (strcmp(command, vtable[i].command) == 0) {
            (*vtable[i].callback)(data);
            return;
        }
    
    是超级通用版本,它将字符串方法名称映射到以单个匿名指针作为参数的函数。您的实际调度表将是以下内容的数组,如下所示(来自INN源代码中tinyleaf的修改示例):

    显然,您对函数了解得越多,就可以创建越具体的原型,并且可以将其他选择条件(例如参数的数量)嵌入到分派表中。(实际INN源具有最小和最大参数计数,以参数结构传递,而不仅仅是void*,并在分派表中包含命令说明。)

    搜索分派表的基本代码非常简单。假设您在
    vtable
    中有一组分派结构项,在
    length
    中有表的长度,类似于:

    typedef void (*dispatch_func)(void *);
    struct dispatch {
        const char *command;
        dispatch_func callback;
    };
    
    for (i = 0; i < length; i++)
        if (strcmp(command, vtable[i].command) == 0) {
            (*vtable[i].callback)(data);
            return;
        }
    
    for(i=0;i

    要实现继承,需要父指针,如果从循环的末尾掉下来,则向上移动到父指针并重复该逻辑。(显然,对于递归函数来说,这可能是一个有用的地方。)

    没有简单的方法可以做到这一点。不过,你可以手动做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;
    };
    
    其思想是每个结构都应该有一个伴随的vtable结构,它存储指向该结构实现的所有虚拟方法的指针。Vtable结构每个只有一个实例。它们应该驻留在静态内存中,并且应该用指向函数的指针初始化。这些指针应该以每个特定结构所需的方式实现虚拟方法。结构本身可以有许多实例。实例中的Vtable数据域应指向其类的静态Vtable结构

    参数
    此\u指针
    传递实例的地址。它应该手动传递。这是一天结束时的C


    注意,您需要分配vtable结构、init vtable指针等,并且需要使用自己的代码手动完成所有这些操作。

    而不是试图将一个圆钉挤到一个方孔中--试图在非OOP语言上强制使用OOP结构,我将使用C++而不是C。@ HoVrCRAFTFulfFeels:我只想在我的C教授中做这件事。这类东西的来源是通过.@ Luuldodog,今天我从一个堆栈溢出的帖子中得到了PDF,但是我找不到我要找的具体的部分。你知道哪一章是关于这个的吗?我不知道!我从来没有读过第二章。我只是假设。我很抱歉。