类继承层次设计问题

时间:2013-07-15 16:04:08

标签: c++ oop inheritance polymorphism

我有以下图表类层次结构:

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。:如果有一些书籍我可以练习这些设计问题,我也很乐意。我遇到这些delimma并且不确定该怎么做。

编辑:

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

class clustering {
    baseGraph *graph;
}

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

3 个答案:

答案 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)

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

  1. 没有(可能会记录尝试,但会被忽略)
  2. 灾难性的失败
  3. 我甚至不能尝试(编译器不应该让我)
  4. 就是这样。这些都是你的选择。

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

    第三个很有趣。这意味着根本没有相应的虚拟功能。不在你的班级,也不在任何基类。这违背了你的设计,但你的设计并不一定完美。

    那么你如何设置标签呢?通过不是指向基类的指针:)它可以是指向另一个基类的指针(一个mixin - 你使用多重继承来为图形添加标签功能)。或者你可以模板化你的设计,这样层次结构就不重要了,你总是静态地知道对象的派生类型。