我不确定我要做的是封装,但它是一个OOP概念。我正在实现二叉树,特别是插入函数:
typedef struct __node* tree;
typedef struct __node { void* data; tree l,r; } node;
typedef struct {int (*cmp)(void* a,void* b); tree root;} avl_tree;
....
void tree_insert(tree node, tree* root, int (*cmp)(void* a,void* b))
{
if (*root==NULL) { *root=node; return; }
int c1 = cmp(node->data, (*root)->data);
if (c1==-1) tree_insert(node, &((*root)->l), cmp);
}
tree tree_new_node(void*data){ tree a = malloc(...); ... return a; }
void avl_insert(void* data, avl_tree* a)
{
tree_insert(tree_new_node(data), &(a->root), a->cmp);
....
}
该模块将通过avl_insert
函数使用,该函数被赋予指向相关平衡树avl_tree
的指针,该树包含指向原始树的指针以及指向比较器的指针。现在,显然应该调用tree insert
和tree_insert
应该可以访问比较器以及我当前正在插入的节点。该函数在二叉树上行走,因此它自然是递归的。但是,如果我给它比较器和当前节点作为参数,它们将在每次递归调用时传递,这是不必要的,因为它们将始终是相同的。
我想避免这样做。我无法想出一个干净又好的解决方案。这些是我能想到的选择:
使用C ++类并使tree_insert
函数成为avl_tree
类的方法。然后它可以通过this
指针访问比较器。这个解决方案的问题是我想使用C而不是C ++。此外,它不会消除当前节点参数的传递。
在函数(或全局数据)中使用静态成员。我不确定我是否可以在每次avl_insert
电话时干净地初始化它们。此外,这个解决方案不是线程安全的。
现在我想起来,这似乎很容易在函数式编程语言中实现。我想知道,这是C的一个根本问题,还是我不知道该怎么做。实现这一目标的最简洁方法是什么?
谢谢!
在我想到Victor Sorokin的回答后,我读到了this
指针,结果发现它是每个成员函数调用中的隐含参数。现在我想到它似乎是唯一合乎逻辑的解决方案。每次调用tree_insert
函数都需要知道它所运行的结构的地址。即使在函数式语言中也不能避免使用额外的指针...
一种可能的解决方案是在每个节点中保留指向主树结构的指针。
所以这是一个基本的“问题”。
答案 0 :(得分:1)
可用于实现封装的一种有趣方法是查看C ++编译器发出的汇编代码,然后将其转换为适当的C代码。
另一种更常规的方法是使用一些C对象库,如GLib。
我认为,这两种方法会产生类似的结果:)
顺便提一下,您提到的第一个选项与第二个选项一样容易受到线程问题的影响。 C ++中没有隐含的线程安全性。
“OOP”C代码 I 在Linux内核(文件系统层)中看到的主要是多态性,而不是封装。通过引入枚举可能的操作(作为函数的指针)的结构来实现多态性。然后创建各种“子类”,每个“子类”使用它自己的一组实现方法初始化该结构。
答案 1 :(得分:0)
您应该能够将该尾递归转换为迭代,并完全避免函数调用。像
这样的东西void tree_insert(tree node,tree*root,int (*cmp)(void*a,void*b))
{
tree* current = root;
while (*current != NULL)
{
int c1=cmp(node->data,(*current)->data);
if(c1==-1)current = &((*current)->l);
else current = &((*current)->r);
}
*current=node;
}
答案 2 :(得分:0)
我的回答已经存在一个问题 - What does “static” mean in a C program?
您可以粗略地将C源文件作为类。关键字 static 使变量或函数只有内部链接,类似于经典OOP中的 private 。
foo.h中
#ifndef FOO_H
#define FOO_H
double publicStuff;
double getter (void);
void setter (double);
int publicFunction (void);
#endif
foo.c的
#include "foo.h"
static double privateStuff;
static int privateFunction (void)
{
return privateStuff;
}
int publicFunction (void)
{
return privateFunction();
}
double getter (void)
{
return privateStuff;
}
void setter (double foo)
{
privateStuff = foo;
}
的main.c
#include "foo.h"
#include <stdio.h>
static double privateStuff = 42;
static int privateFunction (void)
{
return privateStuff;
}
int main (void)
{
publicStuff = 3.14;
setter(publicStuff);
printf("%g %d %d\n", getter(), publicFunction(), privateFunction());
return 0;
}