我有以下图表类层次结构:
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 matGraph
和class listGraph
的实现都是不同的,它们分别是图的邻接矩阵表示和邻接列表表示。现在无需更改这些图表的标注版本的定义,因此我不会在lListGraph
和lMatGraph
现在我唯一的问题是setLabel(const ArratI &)
和lListGraph
类lMatGraph
。我需要这个函数是虚函数,以便通过基类指针调用它,但同时我没有类matGraph
和listGraph
的标签。
我不知道我的设计层次是否正确,但对我来说似乎很直观。所以对此的任何评论都会很好。我可以用setLabel
函数做什么。是否可以拥有这样的功能(对我而言,这看起来像是一种解决方法,所以这个问题)或者我是否需要重新考虑我的类层次结构。
P.S。:如果有一些书籍我可以练习这些设计问题,我也很乐意。我遇到这些delimma并且不确定该怎么做。
编辑:
使用类图在另一个类clustering
中使用,其中我有一个成员baseGraph *graph
,即
class clustering {
baseGraph *graph;
}
我在这里存储指向基类的指针,以便我可以使用class graph
中的不同算法(实现为函数)。对于聚类类,它又取决于我想要使用的图形类型。
答案 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(typeo)继承你错误地从图中继承 - 尽管它不是归结为同一点。
粗略编码,如果您有疑问或有错误,请随时提出。
答案 1 :(得分: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)
中讨论答案 2 :(得分:0)
这一切归结为一个简单的选择。如果我尝试在图形中设置一个实际上不支持标签的标签,会发生什么?
就是这样。这些都是你的选择。
前两个选项很简单,您只需编写一个报告错误的虚函数(记录它或引发异常)。
第三个很有趣。这意味着根本没有相应的虚拟功能。不在你的班级,也不在任何基类。这违背了你的设计,但你的设计并不一定完美。
那么你如何设置标签呢?通过不是指向基类的指针:)它可以是指向另一个基类的指针(一个mixin - 你使用多重继承来为图形添加标签功能)。或者你可以模板化你的设计,这样层次结构就不重要了,你总是静态地知道对象的派生类型。