2016-04-30 37 views
4

現在我知道你在想什麼 - 我在標題中描述的事情聽起來就像超載。我知道這不是C中的事情,反正我也不會去做。我有這兩個功能 - 在他們的身體中絕對是一樣的,但參數是兩個不同的結構。基本上它是一個二叉搜索樹結構和一個紅黑樹結構。正如你可能知道的結構只有一個區別 - 紅黑樹結構包含一個字段,這是一個顏色。此外,功能搜索,最小,最大,前任,後繼..那些將有完全相同的身體,但唉,他們採取2種不同類型的結構。當然,插入和刪除方法會有所不同。如何在這種情況下不重複自己? C函數是相同的但具有不同的參數

所以我在想如何避免打破編程中的頭號規則,而不是重複自己?我想到了很多解決方案,但是當我試圖找到實現它的方法時,沒有任何工作。我想過只是使用一個函數,但我不能這樣做,因爲結構是不同的。我想過使用宏,但老實說,我不知道如何使這些工作,我甚至不知道他們可以避免我有兩個不同的結構的問題。我考慮過製作一個泛型結構,並讓rb結構包含它和一個顏色變量,但是這直接改變了代碼中的幾個字符無處不在,因爲我必須更深層次地訪問結構以獲取值並且我不再擁有這些值重複的代碼。

的問題是什麼樣的只是一個例子:

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

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

如果我是在Java編碼,我可能會解決這個使用抽象超類,但C沒有這樣花哨的東西。

一些額外的信息:兩個實現都有自己的頭文件和類文件,我想保持這種方式。現在我在這兩個類中重複了代碼,唯一不同的是函數和結構的名稱(除了c的插入和刪除函數)。

對不起,如果這有一個明顯的解決方案,我只是沒有找到一個出路,而不重複我的代碼。

+0

如果您不想通過擁有泛型結構來更改所有其他代碼,請在兩個調用函數(每種類型都使用一個函數)中進行更改。將相關成員複製到您的公共結構中,並調用搜索功能。 –

+0

第一條規則當然不是乾的。我會先把KISS。但是,當然,你會得到一個不同的答案,你要求的每個程序員的第一條規則應該是什麼...... – cmaster

回答

2

如果您有bstTree作爲這樣的第一個成員創建rbTree

typedef struct 
{ 
    bstTree common ; 
    int color ; 
} rbTree 

然後你就可以放心地施放rbTreebstTree,所以rb_search()可以實現爲一個簡單的宏這樣的:

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

一個問題是,現在對於rbTree唯一的任何代碼,您必須通過012hm訪問大多數成員餘燼。然而,這並非完全必要;如果您沒有將rbTreebstTree成員一起定義,但只要確保兩者的定義與普通成員第一次相同並且順序和類型相同,就可以將其中一個轉換爲另一個並訪問成員,只要相同的包裝和對齊選項適用於所有使用該結構的模塊 - 但這樣做的安全性較差,維護也較差。做到這一點有點醜陋但更安全的方法是將常見成員放在包含文件和每個結構定義中的成員中。

+0

最佳答案。這是Windows API如何處理舊版結構的新版本。 –

+0

我總是這樣定義宏:'#define rb_search(t,k)bst_search(&(t) - > common,k)''''''''''''''''''用'rb_search(hashTablePointer,「foo」)''。 – cmaster

+0

我喜歡這個版本,但是當我開始實現它時,我記得 - 通用bstTree有3個指針 - 父,左和右,它們都是bstTree指針。所以如果我有一個包含一個bstTree的rbTree,它包含指向其他bstTree的指針,那麼rbTree節點之間就沒有連接。哪個比擊敗樹的目的。有沒有任何解決方法,這不涉及更多的代碼重複?我應該繼續爲每個不同的樹做相同的代碼嗎? – user3212138

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。通過將主體移動到單獨的包含文件。稍微多一點工作,但是如果函數非常大或者您需要一次生成完整的函數系列(例如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 
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,當他們期望只有一個,如果這些類型。

這種方法的缺點是您爲單個樹需要更多內存,因爲您保留了另一個樹的成員。可能你可以用一些工會來緩解它。

相關問題