2010-09-23 43 views
1

我真的不知道如何在標題中指定問題,所以這裏是它的要點。並行繼承樹,其中來自一棵樹的類具有來自另一棵樹的類的容器

我正在寫圖形類Graph,Node和Edge,然後將它們繼承到VisGraph,VisNode和VisEdge中以獲取可繪製圖形(使用C++)。然後我需要進一步將這些分類到依賴於某些數據的特定類中。所以我有很多平行的繼承:

 
Graph -- VisGraph -- RouteGraph 

Node -- VisNode -- RouteNode 

Edge -- VisEdge -- RouteEdge 

這是相當醜陋,我開始這樣做,這樣我就逐步實現的功能,但也有很多問題。例如,其中之一就是基類具有圖中所有節點實例的容器。問題是,如果我在VisGraph中處理VisNode的函數,它需要VisNode的唯一功能,我必須在基類的容器中獲取的節點上執行dynamic_cast。

也許我應該寫一個包含Graph並繪製它的「Vis」類? 我發現繼承方便,因爲每個節點/邊緣可以很容易地繪製自己而不是我 存儲關於位置等外部的額外信息,並繪製它們都單獨。

你有任何建議/設計模式,可以使這更優雅?

預先感謝您。

回答

1

如果有疑問,在這個問題拋出的模板,直到其投降:

template <typename N, typename E> 
class Graph { 
    std::vector<N> nodes; 
    std::vector<E> edges; 
}; 

typedef Graph<VisNode, VisEdge> VisGraph; 
typedef Graph<RouteNode, RouteEdge> RouteGraph; 

你失去了繼承(RouteGraph不再VisGraph繼承),但這是正常的C++容器類型和圖表有些像一個容器。不過,您可以保留Node - > VisNode - > RouteNode之間的繼承關係。

由於節點和邊緣應該是匹配類型,你可以走得更遠,並給Graph一個單一的模板參數,它本身是一個包含邊緣和節點類型的類作爲typedefs。不過,我不確定這是否值得。

編輯

由於要陸續添加功能,你可以繼續繼承的一種形式,但失去的多態性:

template <typename N, typename E> 
class GraphImpl { 
    std::vector<N> nodes; 
    std::vector<E> edges; 
}; 

template <typename N, typename E> 
class VisGraphImpl : public GraphImpl<N, E> { 
    // constructors 

    // extra functions 
}; 

template <typename N, typename E> 
class RouteGraphImpl : public VisGraphImpl<N, E> { 
    // constructors 

    // extra functions 
}; 

typedef GraphImpl<Node, Edge> Graph; 
typedef VisGraphImpl<VisNode, VisEdge> VisGraph; 
typedef RouteGraphImpl<RouteNode, RouteEdge> RouteGraph; 

有可能是一個更好的辦法,但是,通過捆綁這些額外的功能成懂事的混入和使用CRTP:

template<typename Derived> 
class VisFunctions { 
    void somfunc() { 
     myself = static_cast<Derived&>(*this); 
     // do stuff 
    } 
}; 

然後:

class VisGraph : public Graph<VisNode, VisEdge>, public VisFunctions<VisGraph> { 
    friend class VisFunctions<VisGraph>; 
}; 

class RouteGraph : public Graph<RouteNode, RouteEdge>, public VisFunctions<RouteGraph>, public RouteFunctions<RouteGraph> { 
    friend class VisFunctions<RouteGraph>; 
    friend class RouteFunctions<RouteGraph>; 
}; 

不知道如何看看你的真實情況。順便說一句,如果你不想/需要額外功能的朋友聲明,那麼你不需要這些額外的功能成爲成員 - 只需讓他們自由的功能,採取VisGraph或RouteGraph參數。

+0

不錯!爲什麼沒有我,雖然如此,哈哈。感謝您的快速回復 - 我會看到如果有任何其他答案出現在接受:) – 2010-09-23 14:50:07

+0

我想過了,如果我確實使用模板,我將無法添加VisGraph和RouteGraph的額外方法,因爲它們是本質上只是一個具有不同容器的Graph。也許我目前的VisGraph/RouteGraph類中有一些模板化的Node/Edge容器? – 2010-09-23 15:28:44

+0

謝謝你,我會用我正在做的這些技巧來嘗試這些技巧!再次感謝! – 2010-09-25 16:13:08