2010-08-05 65 views
3

假設我有一個數據類型enum TreeTypes { TallTree, ShortTree, MediumTree }如何根據變量值習慣性地調用C++函數?

我必須根據一種特定的樹類型初始化一些數據。

目前,我寫了這個代碼:

int initialize(enum TreeTypes tree_type) { 
    if (tree_type == TallTree) { 
     init_tall_tree(); 
    } 
    else if (tree_type == ShortTree) { 
     init_short_tree(); 
    } 
    else if (tree_type == MediumTree) { 
     init_medium_tree(); 
    } 
    return OK; 
} 

但這是某種愚蠢的代碼的重複。我沒有使用任何強大的C++功能,如模板。

我怎樣才能更好地編寫這段代碼?

謝謝,博大Cydo。

+1

看起來像改善你的代碼應該從設計開始。你可以嘗試用if(){} else {}這樣的巧妙使用其他語言特性來取代舊的控制結構,但我懷疑它會改進代碼。寫更多關於這個問題本身。你想要建模什麼? – 2010-08-05 20:09:56

+0

我使用的代碼更復雜。我試圖用一個非常小的例子簡化它。我正在研究非常大的項目,並且在一個地方用戶可以有各種數據類型(這裏我稱它們爲TallTree,ShortTree,MediumTree)。對於每種數據類型,我都必須採取一些行動。在我的情況下,它是12種不同的類型,所以我的if/else if/else if /是12不同的if/else if/...語句。很壞。 – bodacydo 2010-08-05 20:17:23

+1

但是,實際調用初始化時,tree_type參數來自哪裏。初始化一個正常的函數或某個類的方法?這些init函數是否對一些全局數據起作用?他們初始化了什麼。沒有參數。他們的方法? – 2010-08-05 20:22:28

回答

16

你的代碼對於兩個或三個值是可以的,但是你是對的,當你有數百個值時,你需要更多的工業強度。兩種可能的解決方案:

  • 使用類層次結構,不枚舉 - 然後你可以使用的虛函數和具有編譯器工作出其實際功能調用

  • 創建地圖枚舉的 - >功能,您在初始化啓動 - 然後你的函數調用變得像map[enum]->func()

模板不工作,以及在這裏,因爲你正試圖使在運行時決定的,而模板編譯做自己的東西-時間。

+2

+1,動態調度是爲這類事物設計的...... – 2010-08-05 20:14:54

+0

函數映射可以使用'boost :: function' /'boost :: bind()'或TR1等價物獲益。 – 2010-08-05 20:25:31

+2

這聽起來像一個虛擬表,C++已經具有虛擬功能和多態性... – joshperry 2010-08-05 21:22:14

0

嘗試switch語句:

int initialize(enum TreeTypes tree_type) { 
    switch (tree_type) { 
     case TallTree: 
      init_tall_tree(); 
      break; 
     case ShortTree: 
      init_short_tree(); 
      break; 
     case MediumTree: 
      init_medium_tree(); 
      break; 
    } 
    return OK; 
} 
+4

與if-else沒有什麼不同,實際上有更多的代碼。 – 2010-08-05 20:09:15

0

如果初始化是真正的唯一的區別,那麼我不知道任何其他成語將改善這一狀況。

您可以從樹中創建子類並創建正確類型的樹對象......但您仍然需要區分要實例化的對象,因此您仍然可以在某處找到類似的if/else塊。這就是說,如果不僅僅是初始化會有所不同,你應該繼承和使用虛擬函數來制定它們之間的差異。

7

在一個字:繼承

class Tree { public: virtual void initialize() = 0; } 

class ShortTree : public Tree { 
public: 
    virtual void initialize(){ 
     /* Short Tree specific code here */ 
    } 
} 

class MediumTree : public Tree { 
public: 
    virtual void initialize(){ 
     /* Medium Tree specific code here */ 
    } 
} 

class TallTree : public Tree { 
public: 
    virtual void initialize(){ 
     /* Tall Tree specific code here */ 
    } 
} 

那麼無論你想調用初始化只要確保有一個指針或多態性能夠正常工作的參考:

Vector<Tree*> trees; 
trees.push_back(new SmallTree()); 
trees.push_back(new MediumTree(); 
trees.push_back(new TallTree(); 

// This will call the tree specific code for each tree in the vector 
for(vector<Tree*>::iterator tree = trees.begin(); tree!=trees.end(); ++tree) 
    tree->initialize(); 
+0

@Justin Ardini我的C++鏽跡正在顯示。固定的。謝謝 – 2010-08-05 20:21:08

+0

你的基類最好有一個虛擬析構函數,假設你曾經對你新建的東西調用delete。 – 2010-08-05 21:59:06

+1

@尼爾巴特沃斯我的代碼已被採納並與...一起運行...我不認識它了:) – 2010-08-05 22:22:22

1

使用查找表即由枚舉值(假設所有函數具有相同的簽名)索引,即:

enum TreeTypes { TallTree, ShortTree, MediumTree, MaxTreeTypes } 

typedef void (*p_init_func)(void); 

p_init_func initialize_funcs[MaxTreeTypes] = 
{ 
    &init_tall_tree, 
    &init_short_tree, 
    &init_medium_tree 
}; 

int initialize(enum TreeTypes tree_type) 
{ 
    initialize_funcs[tree_type](); 
    return OK; 
} 
0

和模板的方式,因爲你已經指出它在你的標籤:

enum TreeTypes { Tall, Short, Medium }; 

struct TreeBase { 
    // (...) 
}; 

struct TallTree : public TreeBase { 
    // (...) 
}; 

struct ShortTree : public TreeBase { 
    // (...) 
}; 

struct MediumTree : public TreeBase { 
    // (...) 
}; 

template<TreeTypes N_type = Tall> 
struct Tree : public TallTree { 
    // (...) 
}; 

template<> 
struct Tree<Short> : public ShortTree { 
    // (...) 
}; 

template<> 
struct Tree<Medium> : public MediumTree { 
    // (...) 
}; 

這樣,你得到了每棵樹類型可由基指針訪問單獨的類。將它們包裝進樹類讓你這樣做:

Tree<Tall> tall_tree; 
Tree<Short> short_tree; 
Tree<Medium> medium_tree;