C 良好的图书馆设计;重叠“;功能
我正在尝试创建一个库,它提供了一个简单的链表实现以及链表的一些泛化,比如堆栈和队列,所有这些都基于基本链表 问题是,我希望有不同的类型和它们自己的“私有”函数,这样您就不会使用“stack_pull(my_queue);”或“queue_pull(my_stack)”,这将导致该特定类型列表的错误行为。我现在能想象的唯一方法是,将基本链表结构包装到其他结构中,用于它们自己的类型,基本上就是这样C 良好的图书馆设计;重叠“;功能,c,C,我正在尝试创建一个库,它提供了一个简单的链表实现以及链表的一些泛化,比如堆栈和队列,所有这些都基于基本链表 问题是,我希望有不同的类型和它们自己的“私有”函数,这样您就不会使用“stack_pull(my_queue);”或“queue_pull(my_stack)”,这将导致该特定类型列表的错误行为。我现在能想象的唯一方法是,将基本链表结构包装到其他结构中,用于它们自己的类型,基本上就是这样 typedef struct node { void *data; list_node
typedef struct node
{
void *data;
list_node *next;
} list_node
typedef struct list
{
list_node *root;
} linked_list;
typedef struct queue
{
linked_list *base;
} queue;
typedef struct stack
{
linked_list *base;
} stack;
linked_list *list_create();
void list_dispose(linked_list **, void (*free_content)(void *));
queue *queue_create();
void queue_dispose(queue **, void (*free_content)(void *));
stack *stack_create()
void stack_dispose(stack **, void (*free_content)(void *));
这样,我必须编写专门的函数,以利用基函数和常量展开来获取实际数据,例如
queue *queue_create()
{
[...] /* Allocate a new queue struct */
tmp_queue->base = list_create();
[...]
return tmp_queue
}
void *stack_pull(stack *s)
{
[...] /* Error checking */
return list_pop_last(s->base);
}
void *queue_pull(queue *q)
{
[...] /* Error checking */
return list_pop_first(s->base);
}
如果我想从基本列表中进行专门化,这是我必须承受的开销吗?还是有一种好的、干净的方法?如果你不介意编译器进行较少的类型检查,你可以使用
typedef
s而不是包装结构,例如typedef结构队列列表
\define queue\u create list\u create
或
inline queue*queue\u create(){return(queue*)list\u create
-后一个选项需要C99或C89的扩展 如果有
inline
关键字,还可以将操作包装到宏中:
#define WRAP_LIST(wrapper) \
struct wrapper {linked_list *root;}; \
inline struct wrapper *wrapper ##_create { \
… \
tmp_queue->base = list_create(); \
… \
} \
… \
typedef struct wrapper wrapper
// note lack of ‘;’ at end of last line
WRAP_LIST(queue);
WRAP_LIST(stack);
(或使用C++)
在另一个结构中包装列表结构是一个很好的处理方法。因为内外结构的对齐和填充要求应该完全相同,所以不应该有额外的运行时开销或内存使用(因为外部结构的对齐和填充只来自内部结构)。 对于处理这些函数/方法的函数/方法,您可以使用inline
消除堆栈或队列函数只是简单重命名(或特殊调用)或列表函数的情况下可能产生的任何开销
inline void queue_dispose(queue **Q, void (*free_content)(void *)) {
list_dispose(&&(*Q->base), free_content);
}
这将确保您获得相同级别的类型检查,但没有运行时开销或额外的代码。除非您使用指向这些函数的指针,否则您不应该遇到问题,如果是,那么您也可以为它们包含常规实现
您应该注意到,在列表结构中放置节点指针作为唯一成员已经是一个应用程序,与在堆栈或队列结构中包装列表相同。这种方法很好,只是不需要
链接列表
结构-这是一个不必要的间接级别。列表是完整的y由其头指针描述,因此您只需要在堆栈和队列中包含头指针:
typedef struct queue
{
list_node *queue_head;
} queue;
typedef struct stack
{
list_node *stack_head;
} stack;
单独的结构是非常合适的-例如,堆栈只需要一个头指针,但如果队列同时有指向列表的头指针和尾指针,则队列效率更高。实际上,我在这个问题中简化了结构,我的实际链表还包含一个长度字段,这样就不必遍历整个列表来计算队列的数量其中的元素!