2012-10-23 67 views
5

例如,我可以有一些像這樣數據結構來表示,菜單可以有子

A 
B 
ba 
bb 
C 
Ca 
D 

現在我有一個二維數組,但這並不是很一般,因爲我需要另一個維度如果我想擴大從2到3的最高水平。有什麼建議嗎?

+0

你需要一個遞歸關係。 –

+1

使用樹?每個節點都有一個標籤,可以有零個或多個孩子,可以推廣到任意數量的嵌套菜單。根節點的標籤被忽略,只考慮其子節點。 – Wug

+0

@Seth我明白你的評論,但我不知道如何將它放入代碼 – dchhetri

回答

6

Composite模式將是一個合適的應用程序在這裏:

Composite Pattern

(維基百科:) http://en.wikipedia.org/wiki/Composite_pattern

你的情況:

  • 創建一個基類叫做「菜單「(這對應於上圖中部件部分)
  • 創建一個名爲「菜單項」(這對應於上述圖中的一部分)
  • 創建稱爲「子菜單」派生類派生類(這對應於上述圖中的複合部分) SubMenu可以包含更多的菜單 - 可以是更多MenuItem或SubMenu的。

您可以通過實現與各子對象的計數器實現的基於它們的插入順序至一合成「子菜單」上菜單元素所需的順序:每次調用aSubMenu.add(newMenuItemOrSubMenu)時間,aSubMenu應該增加自己的計數器和標記的新項目與訂購號碼。 (實現的精確細節是你的,你不必在所有使用單獨的計數器,只使用一個列表或數組)

+0

謝謝s.chen。 – dchhetri

2

也許這:

class MenuNode 
{ 
public: 
    MenuNode(std::string new_label); 
    void Add(MenuNode * new_node); 
private: 
    std::string label; 
    std::vector<MenuNode *> children; // changed to vector to preserve order 
}; 

用法:

MenuNode menu("root"), 
     file("File"), 
     edit("Edit"), 
     open("Open..."), 
     close("Close"), 
     save("Save..."), 
     prefs("Preferences"), 
     yes_foo("Activate Foo"), 
     no_foo("Deactivate Foo"); 

menu.Add(&file); 
menu.Add(&edit); 

file.Add(&open); 
file.Add(&close); 
file.Add(&save); 

edit.Add(&prefs); 

prefs.Add(&yes_foo); 
prefs.Add(&no_foo); 

表示:

Main Menu 
    File 
    Open... 
    Close 
    Save... 
    Edit 
    Preferences 
     Activate Foo 
     Deactivate Foo 

提防着明顯的缺陷與這個例子中,ADDRES的依賴(可能)臨時變量。你將無法在函數中創建它並返回它。

實現的瑣碎部分也丟失了,例如沒有辦法遍歷示例代碼中節點的私有狀態。

+0

我想我會推薦動態內存和'unique_ptr'。這個答案缺乏封裝。但這個答案是正確的想法。 –

+0

等等,不,該矢量應該直接包含'MenuNode's。 http://ideone.com/kU2RPa –

+0

將爲所有向量實現或工作做存在不使用間接平的嗎? – Wug

1

使用樹。無論如何,這在樹中最好定義。

其中:rootNode連接到AB,C,DB連接到babbC連接到Ca。等等

enter image description here

1

桑普森臣所說的複合設計模式是爲實現我做了一個小的開發者監視器的正確方法,讓你選擇從菜單結構中的一些測試方法。

我有一個基類的「菜單項目」我從中導出的子菜單和葉子(菜單項)。一個葉子只是執行一些事情,而一個子菜單打開另一個菜單級別。

例如基類可能喜歡類似(如果你喜歡用shared_pointers):

/*************************************************************//*! 
* @brief The base class for all menu entry types (sub menus and sub menu entries/items) 
******************************************************************/ 
class MenuEntry : public boost::enable_shared_from_this<MenuEntry> 
{ 

    public: 
    virtual ~MenuEntry(){} 

/**************************************************************//*! 
* @brief Default implementation to add menu entries; has to be re implemented 
* @param[in] newSubMenuEntry - the new menu entry (another sub menu or leaf) 
**************************************************************/ 
virtual void add(boost::shared_ptr<MenuEntry> newSubMenuEntry)=0; 

/*****************************************************************//*! 
* @brief Default implementation for call to menu entries; always returns false 
* @return false - the function has not been re implemented 
****************************************************************/ 
virtual bool call(void) 
{ 
    // the member function has not been re-implemented 
    return false; 
} 

/*****************************************************************************//*! 
* @brief Default implementation, has to be reimplemented 
* @return emptyVector - an empty vector 
*********************************************************************************/ 
virtual std::vector<boost::shared_ptr<MenuEntry> > getChildren(void) 
{ 
    std::vector<boost::shared_ptr<MenuEntry> > emptyVector; 
    return emptyVector; 
} 


/*******************************************************************************//*! 
* @brief Gives a pointer to the parent of the actual menu entry 
* @return m_parent - pointer to the parent 
******************************************************************************/ 
boost::shared_ptr<MenuEntry> parent(void) 
{ 
    return m_parent; 
} 

/***************************************************************************//*! 
* @brief Default implementation for selecting a menu entry 
* @param[in] desiredMenuEntry - the desired menu entry which shall be selected 
* @return notExisting - a pointer to <b>this</b> 
**********************************************************************************/ 
virtual boost::shared_ptr<MenuEntry> select(boost::shared_ptr<MenuEntry> desiredMenuEntry)=0; 

/**************************************************************************//*! 
* <B>Criticality: C0 \n\n</B> 
* @brief Sets a pointer to the parent of new menu entry 
* @param[in] pointerToParent - pointer to the parent 
****************************************************************************/ 
void setParent(boost::shared_ptr<MenuEntry> pointerToParent) 
{ 
    m_parent = pointerToParent; 
} 

/***************************************************************************//*! 
* @brief Default implementation for destroying children 
*****************************************************************************/ 
virtual void destroy(void)=0; 

    protected: 
    /************************************************************************//*! 
    * @brief Constructor for a menu entry (sub menu or leaf) 
    * @param[in] menuEntryName - the name for the sub menu or leaf 
    *************************************************************************/ 
    MenuEntry(std::string menuEntryName) 
    { 
     m_menuEntryName = menuEntryName; 
    } 

}; 

在選擇方法我通過檢查返回值是否如果我有執行什麼葉,或子菜單,爲此我必須改變我的指針。

爲了方便,你可以添加哪些找到你所有的子菜單中的子菜單項顯示其結構與您實際菜單路徑或類似的標題行的方法,或方法...另一個想法是對的方法掃描菜單樹以避免雙重菜單項asf。