假设我有一个 Stack,我想用它来存储各种不同的类型。如果我定义接口如下:
// stack.h
typedef struct Stack {
size
push // function pointers
pop
etc.
};
假设我想支持两种不同的堆栈类型,所以我创建了:
// stack.c
Stack person_stack;
person_stack->push = push_to_person_stack;
Stack animal_stack;
animal_stack->push = push_to_animal_stack;
如何才能使 push_to_<type>_stack
有效地私有并且该堆栈的调用者只能看到 Stack->push
函数?或者,这在 C 中是不可能的,您需要一种面向对象的语言来做到这一点,但是有一个统一接口的例子是什么?
答案 0 :(得分:1)
您可以使用函数指针来模拟其他 OOP 语言中的方法,但您仍然需要将实例传递给该方法,否则无法知道要推送到哪个堆栈上。同样使用 void*
会产生比它解决的更多的问题。
struct Stack {
void (*push)(Stack* self, void* data); //< self here
}
这是我使用宏在 c 中模拟模板/泛型的方法(参考:https://github.com/wren-lang/wren/blob/main/src/vm/wren_utils.h#L16)
#define DECLARE_STACK(type) \
typedef struct { \
type* data; \
int size; \
int capacity; \
} type##Stack; \
void type##Stack_push(type##Stack* self, type value); \
type type##Stack_pop(type##Stack* self); \
void type##Stack_init(type##Stack* self); \
#define DEFINE_STACK(type) \
void type##Stack_push(type##Stack* self, type value) { \
if (self->capacity <= self->size + 1) { \
self->capacity = self->capacity * 2; \
self->data = realloc(self->data, sizeof(type) * self->capacity); \
} \
self->data[self->size] = value; \
self->size++; \
} \
\
type type##Stack_pop(type##Stack* self) { \
self->size--; \
return self->data[self->size]; \
} \
\
void type##Stack_init(type##Stack* self) { \
self->size = 0; \
self->capacity = 2; \
self->data = malloc(sizeof(type) * self->capacity); \
} \
typedef struct Person {
int id;
} Person;
DECLARE_STACK(Person); // in person.h
DEFINE_STACK(Person); // in person.c
int main() {
Person p1, p2, p3, p4;
p1.id = 1; p2.id = 2; p3.id = 3; p4.id = 4;
PersonStack stack;
PersonStack_init(&stack);
PersonStack_push(&stack, p1);
PersonStack_push(&stack, p2);
PersonStack_push(&stack, p3);
Person p;
p = PersonStack_pop(&stack); // p.id = 3
p = PersonStack_pop(&stack); // p.id = 2
PersonStack_push(&stack, p4);
p = PersonStack_pop(&stack); // p.id = 4
p = PersonStack_pop(&stack); // p.id = 1
return 0;
}
如果你想调试,宏很难用调试器调试流程,所以我使用了一个 python 脚本在编译之前生成宏的扩展到源文件和头文件(我用 scons 构建,它是基于python,所以我自动生成源文件)