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分别是图的邻接矩阵表示和邻接表表示。现在不需要更改这些图的标记版本的定义,所以我不再定义这些lListGraph函数lMatGraph

现在我唯一遇到的问题是setLabel(const ArratI &)在课堂上lListGraphlMatGraph我需要这个函数是虚拟的,以便通过基类指针调用它,但同时我没有任何东西,例如类的标签matGraphlistGraph.

我不知道我的设计层次是否正确,但对我来说似乎很直观。因此,对此的任何评论都会很好。我可以用这个setLabel功能做什么。是否可以拥有这样的功能(对我来说,这看起来像是一种解决方法,所以这个问题)还是我需要重新考虑我的类层次结构。

PS:如果有一些书可以让我练习这样的设计问题,我也很高兴。我经常遇到这些delimma,不知道该怎么办。

编辑:

类图的使用在clustering我有成员的另一个类中使用,baseGraph *graph

class clustering {
    baseGraph *graph;
}

我在这里存储指向基类的指针,以便我可以使用不同的算法(实现为函数)class graph。对于聚类类,它再次取决于我要使用的图形类型。

4

3 回答 3

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) 继承时,你错误地从 graph 继承了 - 即使它归结为同一点。

还有粗略的编码,如果您有问题或有错误,请随时提出。

于 2013-07-15T17:00:45.267 回答
0

这一切都归结为一个简单的选择。如果我尝试在实际上不支持标签的图表中设置标签,会发生什么?

  1. 无(尝试可能会被记录,但会被忽略)
  2. 灾难性的失败
  3. 我什至不能尝试(编译器不应该让我)

而已。这些都是你的选择。

前两个选项很简单,您只需编写一个报告错误的虚函数(记录错误或抛出异常)。

第三个很有趣。这意味着根本没有对应的虚函数。不在您的班级中,也不在任何基类中。这违背了你的设计,但你的设计不一定是完美的。

那么如何设置标签呢?通过不是指向您的基类的指针的东西:) 它可以是指向另一个基类的指针(一个混合 - 您使用多重继承向图形添加标签功能)。或者您可以将您的设计模板化,这样层次结构并不重要,并且您总是静态地知道您的对象的最衍生类型。

于 2013-07-15T17:14:05.850 回答
0

你说setLabel应该通过基类指针调用,所以这必然意味着它应该在基类中声明,即使它没有意义。您可以setLabel通过两种可能的方式实现未标记的图形:

  • 什么都不做 - 忽略设置标签的请求
  • 抛出异常(例如abort) - 可能有问题,所以用户应该知道!

每种方式都是一种解决方法,因此您应该考虑为什么setLabel应该通过基类指针调用,并可能更改此决定。我希望,如果您真的需要为您的算法使用标记图,请使用适当的类型而不是基类类型 - 那么您不需要对基类进行任何修改。

请注意,如果您继续向与每个派生类对应的基类添加内容,那么您最终会在基类中遇到很多混乱- 不好!


此外,以下内容可能会解决您的问题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
}

这在 Effective C++ 一书中进行了讨论(Effective C++ Item 23 Prefer non-member non-friend functions to member functions

于 2013-07-15T17:10:49.840 回答