比C ++中的dynamic_cast更好的解决方案

时间:2014-05-09 16:02:06

标签: c++ inheritance software-design

我有一个我为我的项目设计的类层次结构,但我不确定如何实现它的一部分。

这是类层次结构:

class Shape { };

class Colored { // Only pure virtual functions
};

class Square : public Shape { };

class Circle : public Shape { };

class ColoredSquare : public Square, public Colored { };

class ColoredCircle : public Circle, public Colored { };

在我的项目的一部分中,我有一个不同类型形状的std :: vector。为了运行算法,我需要将它们放在一个有色对象的std :: vector中(所有这些都是不同具体形状的派生类型,所以我需要一个方法将Square转换为ColoredSquare和Circle into运行时的ColoredCircle。 棘手的是,“形状”类与“彩色”类位于不同的库中。 实现这个目标的最佳方法是什么?我曾考虑过做一个dynamic_cast检查,但如果有更好的方法,我宁愿选择那个。

编辑1:

以下是一个更好的示例:

class Traceable {
    public:
        // All virtual functions
        virtual bool intersect(const Ray& r) = 0;
        // ...
};

class TraceableSphere : public Sphere, public Traceable {
};

class IO {
    public:
        // Reads shapes from a file, constructs new concrete shapes, and returns them to
        // whatever class needs them.
        std::vector<Shape*> shape_reader(std::string file_name);
};

class RayTracer {
    public:
        void init(const std::vector<Shape*>& shapes);
        void run();
    private:
        std::vector<Traceable*> traceable_shapes;
};

void RayTracer::init(const std::vector<Shape*>& shapes) {
    // ??? traceable_shapes <- shapes
}

void RayTracer::run() {
    // Do algorithm
}

5 个答案:

答案 0 :(得分:4)

您可以使用装饰器模式:

class ColorDecorator public Colored
{
    ColorDecorator(Shape* shape): m_shape(shape) {}
    ... //forward/implement whatever you want
};

如果你想在一个彩色矢量中存储一个Square,请将它包装在这样的装饰器中。

这是否有意义是值得怀疑的,这取决于您的设计和替代方案。为了以防万一,还要查看访客模式(也称为双重调度),您可以使用它来访问容器中的对象子集,或者根据其类型对它们进行不同的处理。

答案 1 :(得分:1)

看起来你要以“is-a”风格设计类库,欢迎来到继承地狱。 你能详细说明一下你的“算法”吗? 通常,如果您需要对对象进行“类型测试”,那么它就是糟糕的设计,因为这是您希望通过多态来避免的。因此,对象应该提供算法使用的正确实现(设计模式:“策略”),高级概念利用“基于策略的类设计”。

答案 2 :(得分:0)

通过精心设计,您可以避免casting。特别是关心SRP。仔细实施方法,以便他们使用单个Interface来实现单一目标/履行单一责任。您尚未发布有关算法或如何使用对象的任何内容。以下是假设的样本设计:

class A {
  public:
        void doSomeThing();
};

class B{
  public:
        void doSomeOtherThing();
};

class C:public A,public B{};

void f1( A* a){
   //some operation
   a->doSomeThing();
   //more operation
}
void f2(B* b){
   //some operation
   b->doSomeOtherThing();
   //more operation

}

int main(int argc, char* argv[])
{
  C c;
  f1(&c);
  f2(&c);

  return 0;
}

注意在不同的上下文中使用对象c。我们的想法是仅使用 interface C与特定目的相关的f。此示例可以包含类而不是函数f2Algorithm。例如,您有一些instance类使用继承层次结构中的对象执行某些操作,您应该创建类,以便它们执行单一职责,大多数情况下需要使用单个接口,然后您只能创建/传递该对象的{{1}}对象。

答案 3 :(得分:0)

如果接口的所有实现以不同的方式实现相同的操作,则面向对象的编程才有意义。面向对象是关于操作的。你没有向我们展示任何操作,所以我们无法告诉你面向对象是否对你的问题有意义。如果它没有意义,你不必使用面向对象的编程,特别是在C ++中,它提供了一些其他管理代码的方法。

至于dynamic_cast - 在精心设计的面向对象的代码中,它应该是罕见的。如果确实需要在某些情况下了解具体类型(并且在现实生活中的软件工程中存在这种情况,特别是当您维护遗留代码时),那么它就是这项工作的最佳工具,并且通过在基类中添加类似virtual Concrete* ToConcrete()的东西来尝试重新实现轮子要清晰得多。

答案 4 :(得分:0)

我认为最简单的&amp;对你来说最干净的解决方案就像以下类似于克里斯在最后提出的建议。

class Shape {
  virtual Colored *getColored() {
    return NULL;
  }
};

class Colored { // Only pure virtual functions
};

class Square : public Shape { };

class Circle : public Shape { };

class ColoredSquare : public Square, public Colored {
  virtual Colored *getColored() {
    return this;
  }
};

class ColoredCircle : public Circle, public Colored {
  virtual Colored *getColored() {
    return this;
  }
};

我不完全理解这句话 “棘手的是,'形状'类与'有色'类在不同的库中。”

这怎么不允许你做这里建议的(但仍然允许你创建一个ColoredSquare类)?