2013-07-15 46 views
2

我對圖形下面的類層次結構:類繼承層次的設計問題

typedef vector<int> ArrayI; 
typedef vector<Array<long>> Mat2DB; 
typedef vector<ArrayI> adjList; 

class baseGraph { 
    int nodes; 
    ArrayI degree; 
    //some member functions. 
} 

class matGraph: public baseGraph { 
    Mat2DB matrix; 
    //member functions. 
} 

class lMatGraph: public matGraph { 
    ArrayI labels; 
    //member functions. 
} 

class listGraph: public baseGraph { 
    adjList list; 
    //member functions. 
} 

class lListGraph: public listGraph { 
    ArrayI labels; 
    //member functions. 
} 
在這個類

現在我有很多其他的功能,主要是虛擬的,所以,當我得到調用適當的功能同時使用基類指針。

例如我有一個功能sssp(int node)它實現單一來源的最短路徑。 class matGraphclass listGraph分別是圖的鄰接矩陣表示和鄰接表表示。目前還沒有需要改變定義這些圖中標記的版本,所以我不lListGraphlMatGraph

重新定義這些功能現在,我就吃了唯一的問題是setLabel(const ArratI &)lListGraphlMatGraph類。我需要這個函數是虛擬的,以便它通過基類指針被調用,但同時我沒有任何東西,例如matGraphlistGraph類的標籤。

我不知道我的設計層次結構是否正確,但對我來說似乎很直觀。所以對此的任何評論都會很好。我該怎麼做setLabel函數。是否可以擁有這樣的功能(對我來說,這看起來像是一種解決方法,所以這個問題)還是我需要重新考慮我的類層次結構。

P.S .:我也很喜歡,如果有些書可以練習這些設計問題。我遇到了這些事情,不知道該怎麼辦。

編輯:

類圖形的使用在另一個類中clustering其中我有一個構件baseGraph *graph

class clustering { 
    baseGraph *graph; 
} 

我存儲指針基類這裏,這樣我可以使用不同的用於算法(實現爲函數)從class graph。對於集羣類,它又取決於我想要使用的圖表類型。

+0

一定要記得'矢量'是專門爲所有其他標準容器不同(你可能已經預期這一點)。 –

+0

@MarkB在我的原始實現中,我使用'vector '來對加權圖形進行建模,所以它很好,但很高興知道它的區別。在輸入我認爲使層次結構簡單的問題時。我將編輯該問題。 –

+0

標籤是否需要能夠在運行時多次更改?或者它會在物體的整個生命中保持不變嗎? –

回答

1

也許這樣?

typedef vector<int> ArrayI; 
typedef vector<Array<long>> Mat2DB; 
typedef vector<ArrayI> adjList; 

class baseGraph { 
    int nodes; 
    ArrayI degree; 
    virtual void sssp(int node); 
    //some member functions. 
} 

class labeledGraph: public virtual baseGraph { 
    ArrayI labels; 
    virtual void setLabel(const ArratI &); 
    //member functions. 
} 

class matGraph: public virtual baseGraph { 
    Mat2DB matrix; 
    //member functions. 
} 

class lMatGraph: public virtual matGraph, public virtual labeledGraph { 
    //member functions. 
} 

class listGraph: public virtual baseGraph { 
    adjList list; 
    //member functions. 
} 

class lListGraph: public virtual listGraph, public virtual labeledGraph { 
    //member functions. 
} 

我假設在這裏,你從錯誤繼承圖時,你應該已經從baseGraph(類型0)繼承 - 雖然就算沒有把它歸結爲同一個點。

也粗略的編碼,如果你有問題或者如果有錯誤,隨意問。

+0

對不起,如果這是天真的,但我從來沒有使用過虛擬和多重繼承。那麼你能否解釋一下我將如何使用'baseGraph'指針調用'setLabels'。 –

+0

如果您通過'baseGraph *'調用它,則沒有選擇,只能將其放在'class baseGraph'上,在這種情況下,其他答案適用。對於我的建議,你可以通過'labeledGraph *'來調用它 - 因爲當有可能設置標籤時,與'labelGraph *'一起工作是有意義的。 難道你不想讓集羣模板? 'template clustering {/*...*/ std :: unique_ptr < GraphType > * graph; ''?在這種情況下,您可以在繼續使用它之前查看一些選項以測試模板類型上setLabel的存在。 –

+0

早些時候,我沒有想到將模板類聚類,但現在我開始喜歡這個想法。我想我會考慮的唯一問題是,如果我在程序過程中需要更改圖形表示(這是一種可能的情況),那麼我將無法做到這一點。 –

0

你說應該通過基類指針調用setLabel,所以這必然意味着它應該在基類中聲明,即使它沒有意義。您可以爲未在兩種可能的方式標示圖形執行setLabel

  • 什麼都不做 - 只是忽略用於設置標籤的要求
  • 拋出一個異常(如abort) - 這很可能是錯的,所以用戶應該知道!

每個方法是一種解決方法,所以你應該考慮爲什麼setLabel應通過基類指針調用,並且可能改變這個決定。我希望,如果你真的需要一個標籤圖來表示你的算法,使用適當的類型而不是基類類型 - 那麼你不需要對基類進行任何攻擊。

請注意,如果您不斷向與每個派生類相對應的基類添加內容,那麼您將以基類中的a lot of mess結束 - 不行!


此外,以下內容可能與setLabel解決您的問題,讓你的類層次結構「健康」。

考慮從類聲明移動你的基本算法,如sssp了 - 讓他們重載獨立的功能,而不是成員函數。這樣你就不需要在基類中聲明sssp。如果你採用這個指南,當你實現一個新的算法時,編譯器會檢查所有的函數調用,並且如果缺少一個錯誤就會發出一個錯誤(這比碰撞或得到不正確的結果要好)。

class baseGraph { 
    int nodes; 
    ArrayI degree; 
    // a minimum number of member functions (e.g. getNode; getEdges) 
} 

class matGraph: public graph { 
    Mat2DB matrix; 
} 

class lMatGraph: public matGraph { 
    ArrayI labels; 
    void setLabel(const ArrayI &); 
} 

int sssp(const matGraph& graph, int node) 
{ 
    // Some code 
} 

int sssp(const lMatGraph& graph, int node) 
{ 
    // Some code; here you can use labels 
} 

這是在有效的C++書(Effective C++ Item 23 Prefer non-member non-friend functions to member functions

+0

我編輯了這個問題來添加一些更多的細節。關鍵是如果我有非成員函數,那麼集羣類將會一團糟,因爲我必須自己照顧每個圖形類型。 –

0

這一切都可以歸結爲一個簡單的選擇進行討論。如果我嘗試在實際上不支持標籤的圖形中設置標籤,會發生什麼?

  1. 沒有(嘗試可能會記錄否則忽略)
  2. 災難性失效
  3. 我不應該也能進行嘗試(編譯器應該不會讓我)

這它。這些都是您的選擇。

前兩個選項很容易,你只要寫一個報告錯誤(原木,或者拋出異常)的虛函數。

第三個是有趣的。這意味着根本沒有相應的虛擬功能。不在你的課堂上,也不在任何基礎課堂上。這違背了你的設計,但你的設計不一定是完美的。

那麼,你如何設置一個標籤呢?通過不是指向基類的指針:)它可以是指向另一個基類的指針(一種混合 - 您使用多重繼承爲圖形添加標籤功能)。或者你可以模擬你的設計,使層次結構並不重要,你總是靜態地知道你的對象的派生類型。