我真的不知道如何在标题中指定问题,所以这是它的要点。
我正在编写图形类Graph,Node和Edge,然后将它们子类化为VisGraph,VisNode和VisEdge以获得可绘制的图形(在C ++中)。然后我需要进一步将它们子类化为依赖于某些数据的特定类。所以我有很多并行继承:
Graph -- VisGraph -- RouteGraph Node -- VisNode -- RouteNode Edge -- VisEdge -- RouteEdge
这非常难看,我开始这样做,所以我会逐步实现功能,但是存在很多问题。例如,其中之一是基类具有图中所有Node实例的容器。问题是,如果我在处理VisNode的VisGraph函数中需要VisNode独有的功能,我必须对从基类中的容器中获取的节点执行dynamic_cast。
也许我应该写一个包含Graph并绘制它的“Vis”类? 我发现继承很方便,因为每个节点/边缘都可以轻松地绘制自己而不是我 存储关于位置等的额外信息并单独绘制它们。
你有什么建议/设计模式可以让这更优雅吗?
提前谢谢。
答案 0 :(得分: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 ++中容器类型是正常的,而Graph有点像容器。您可以保持节点之间的继承 - &gt; VisNode - &gt;但是,RouteNode。
由于节点和边缘应该是匹配类型,你可以更进一步,并给Graph一个模板参数,它本身是一个包含边和节点类型为typedef的类。不过,我不确定它是否值得。
修改
由于你想连续添加函数,你可以保留一种继承形式但是会失去多态性:
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;
但是,通过将这些额外的功能捆绑到合理的mixins并使用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参数的自由函数。