gpt4 book ai didi

c - 用 C 实现基本的 vtable

转载 作者:行者123 更新时间:2023-12-03 16:31:47 24 4
gpt4 key购买 nike

我正在尝试在 C 中模拟 vtable 的最基本(玩具)案例。这是一个基本示例:

typedef struct Person {
int id;
char *name;
} Person;
假设我们添加了一个方法(即函数指针):
typedef struct Person {
int id;
char *name;
void (*print_name)(Person);
} Person;
现在我们将初始化它并用这个填充部分(让我们忽略内存泄漏):
#include <stdio.h>
#include <stdlib.h>

typedef struct Person Person;
typedef struct Person {
int id;
char *name;
void (*print)(Person *self);
} Person;

void print_name(Person *person) {
printf("Hello %s\n", person->name);
}
Person *init_person(void) {
Person *person = malloc(sizeof(Person));
person->print = print_name;
}
int main(void) {
Person *p = init_person();
p->name = "Greg";
p->print(p);
return 0;
}
运行代码 here .
如果我要从 Person 中取出函数并将其放入 Person_VTable ,例如以下内容:
typedef struct Person {
int id;
char *name;
Person_VTable *vtable;
} Person;

typedef struct Person_VTable {
???
} Person_VTable;
(1) 创建 vtable 和 (2) 用新的 vtable 初始化 Person 对象的正确方法是什么?请注意,我知道这是一个完全微不足道的例子,可以用更好的方式完成,但我看到了如何使用我正在工作的主要对象的外部“vtable”来完成。
此外,这是否也意味着如果我有一个 vtable,而不是只有一个“自我”来引用它来自 struct 中的对象?本身,例如:
void (*print)(Person *self);
我需要 两个间接,所以我知道对象和虚表位置?就像是:
void (*print)(Person *self_obj, Person_VTable *self_vt);
如果是这样,那是很多开销!

最佳答案

一个基本的 vtable 只不过是一个包含函数指针的普通结构,可以在对象实例之间共享。有两种基本方法可以实现它们。一种是使 vtable 指针成为一个普通的结构成员(这就是它在 C++ 中的工作原理):

#include <stdio.h>
#include <stdlib.h>

typedef struct Person Person;
typedef struct Person_VTable Person_VTable;

struct Person {
int id;
char *name;
const Person_VTable *vtable;
};

struct Person_VTable {
void (*print)(Person *self);
};

void print_name(Person *person) {
printf("Hello %s\n", person->name);
}

static const Person_VTable vtable_Person = {
.print = print_name
};

Person *init_person(void) {
Person *person = malloc(sizeof(Person));
person->vtable = &vtable_Person;
return person;
}

int main(void) {
Person *p = init_person();
p->name = "Greg";
p->vtable->print(p);
return 0;
}
另一种是使用胖指针(这就是它在 Rust 中的实现方式):
#include <stdio.h>
#include <stdlib.h>

typedef struct Person Person;
typedef struct Person_VTable Person_VTable;

typedef struct Person_Ptr {
Person *self;
const Person_VTable *vtable;
} Person_Ptr;

struct Person {
int id;
char *name;
const Person_VTable *vtable;
};

struct Person_VTable {
void (*print)(Person_Ptr self);
};

void print_name(Person_Ptr person) {
printf("Hello %s\n", person.self->name);
}

static const Person_VTable vtable_Person = {
.print = print_name
};

Person_Ptr init_person(void) {
Person_Ptr person;
person.self = malloc(sizeof(Person));
person.vtable = &vtable_Person;
return person;
}

int main(void) {
Person_Ptr p = init_person();
p.self->name = "Greg";
p.vtable->print(p);
return 0;
}
在 C 中,首选方式是前者,但这主要是出于语法原因:按值在函数之间传递结构没有广泛认可的 ABI,而传递两个单独的指针在语法上相当笨拙。在将 vtable 附加到内存布局不受您控制的对象时,另一种方法很有用。
本质上,vtables 相对于普通函数指针成员的唯一优势是它们节省内存(结构的每个实例只需要携带一个 vtable 指针)并防止内存损坏(vtables 本身可以驻留在只读内存中)。

关于c - 用 C 实现基本的 vtable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66040677/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com