在这种情况下如何不重复自己? C函数相同但参数不同

时间:2016-04-30 19:03:52

标签: c struct

现在我知道你在想什么 - 我在标题中描述的东西听起来就像重载一样。我知道这不是C中的事情,反正我也不会这样做。我有这两个函数 - 它们的身体绝对相同,但参数是两个不同的结构。基本上它是二叉搜索树结构和红黑树结构。您可能知道结构只有一个区别 - 红黑树结构包含一个字段,而这是一个颜色。还有函数search,min,max,predecessor,successor ......那些将具有完全相同的主体但是它们采用2种不同类型的结构。当然插入和删除方法也不同。

所以我在想如何避免打破编程中的头号规则而不重复自己?当我试图找到实现它的方法时,我想到了很多解决方案但没有工作。我想过只为两者使用一个函数,但我不能这样做,因为结构是不同的。我想过使用宏但老实说我不知道​​如何使这些工作,我甚至不确定他们可以避免我有2个不同的结构的问题。我想过制作一个通用结构并让rb结构包含它和一个颜色变量,但是这个直接改变代码到处都是几个字符因为我必须更深入到结构中以获得值而我不再拥有重复的代码。

只是问题的一个例子:

bst_search(bstTree t, char *k)
{
    // Searching in tree
}

rb_search(rbTree t, char *k)
{
    // SAME code for searching in tree
}

如果我在java中编码,我可能会使用抽象的超类来解决这个问题,但是C没有这样的花哨的东西。

一些额外的信息:两个实现都有自己的头文件和类文件,我想保持这种方式。现在我在这两个类中都有重复的代码,唯一不同的是函数和结构的名称(除了插入和删除函数ofc)。

很抱歉,如果这有一个明显的解决方案,我只是没有找到解决方法而不重复我的代码。

3 个答案:

答案 0 :(得分:2)

如果您创建rbTreebstTree作为第一个成员:

typedef struct
{
   bstTree common ;
   int color ;
} rbTree

然后,您可以安全地将rbTree转换为bstTree,因此rb_search()可以实现为简单宏:

#define rb_search(t, k) bst_search( (bstTree*)(t). k )

现在的问题是,对于rbTree独有的任何代码,您必须通过common成员访问大多数成员。然而,这并非完全必要;如果您没有使用rbTree成员定义bstTree,但只是确保两者的定义与公共成员首先相同且顺序和类型相同,那么您将能够将其中一个定义为另一个只要相同的打包和对齐选项应用于使用该结构的所有模块,就可以访问这些成员 - 但这样做的安全性却低得多,维护起来也不那么容易。一种有点丑陋但更安全的方法是将公共成员放在一个包含文件中,并将#include成员放在每个结构定义中。

答案 1 :(得分:0)

在C语言中没有很好的方法(与C ++完全相同的模板存在相比)。

丑陋的方式#1。通过使用宏:

#define MAKE_SEARCH_FUNCTION(FN_NAME, VAR_TYPE) \
FN_NAME(VAR_TYPE t, char *k) \
{ \
    /* Searching in tree */ \
}

struct bstTree {
};
MAKE_SEARCH_FUNCTION(bst_search, struct bstTree*)

struct rbTree {
};
MAKE_SEARCH_FUNCTION(rb_search, struct rbTree*)

丑陋的方式#2。通过将body移动到单独的include文件中。更多工作,但如果功能非常大或者您需要一次生成整个函数系列(例如bst_search() / bst_add() / bst_remove()),则有意义。

// header.h

FN_NAME(VAR_TYPE t, char *k) 
{
    // Searching in tree
}

// source.c

struct bstTree {
};
#define VAR_TYPE struct bstTree*
#define FN_NAME bst_search
#include "header.h"
#undef VAR_TYPE
#undef FN_NAME

struct rbTree {
};
#define VAR_TYPE struct rbTree*
#define FN_NAME rb_search
#include "header.h"
#undef VAR_TYPE
#undef FN_NAME

答案 2 :(得分:0)

作用于通用输入树的宏会成功,但我发现该解决方案有点脏。

另一种方法是将两个树的所有成员放在一起的通用结构,而不使用嵌套结构。例如:

struct genericTree {
  // common members for both trees 
 ... 
  // members for rb trees 
 ... 
  // members for bst
 ... 
} 

然后你有一个功能:

search(genericTree* t, char* k) 

要保留语义,请使用typedef:

typedef genericTree bstTree;
typedef genericTree rbTree;

所以你仍然可以拥有获得bstTree或rbTree的函数,如果他们只期望这些类型的话。

这种方法的缺点是你为一棵树占用了更多的内存,因为你保留了另一棵树的成员。你可以用一些工会来缓解它。