在C++中映射两个对象类型

Mapping two object types in C++

本文关键字:两个 对象 类型 C++ 映射      更新时间:2023-10-16

我正在C++创建一个小型模拟框架。我想将纯模拟相关的东西与显示分开。所以我有这样的课程:

class Pointer : public SimulationObject {};
class Particle : public SimulationObject {};
class LearningObserver : public SimulationObject {};

它们都派生自SimulationObject,但只有一些(!)具有可视化表示:

class Renderable {
public:
    virtual void render() const = 0;
//may also include reference to assosciated SimulationObject
}
class PointerRenderable : public Renderable {
    void render() const { std::cout << "Render a pointer" << std::endl;
};
class ParticleRenderable : public Renderable {
    void render() const { std::cout << "Render a particle" << std::endl;
};

现在,每当将新的模拟对象添加到我的模拟中(在运行时)时,我都想检查是否有一个类来渲染它。如果是这样,我想创建一个实例。我的第一个想法是使用多态:

class AbstractRenderFactory {
   virtual Renderable * provideRenderable(SimulationObject * so) const = 0;
};
class ConcreteRenderFactory {
   void PointerRenderable * provideRenderable(Pointer * pointer) {
       return new PointerRenderable();
   }
   // further provideRenderable's
};

但是,在重写方法时使用派生类型显然不起作用(调用基方法)。这也是有问题的,因为该函数只会被部分定义。

另一个想法是提供类型的实际映射:

std::map<std::type_index, std::type_index> renderTable;

但我无法仅使用type_info获取实例。你有想法吗?


更新:我尝试使用访问者模式,但是遇到了类似的问题。我的访客类如下所示:

class RenderVisitor {
public:
    virtual Renderable * visit(SimulationObject * so) {
         // I would like to have this method abstract, but I could live with this
         return 0;
    }
};
class MyRenderVisitor : public RenderVisitor {
public:
    Renderable * visit(Pointer * pointer) const {
        return new PointerRenderable();
    }
};

加上我的模拟部件的新基类。

class SimulationObject {
public:
    Renderable * accept(RenderVisitor * renderer) {
        return renderer->visit(this);
    }
};

MyRenderVisitor 的访问方法显然不被认为是基类的覆盖,但我希望通过 this 指向实际(派生)类型,调用正确的方法(MyRenderVisitor 的方法)。

我的测试场景如下所示:

RenderVisitor * rv = new MyRenderVisitor();
SimulationObject * pointer = new Pointer();
Renderable * renderable = pointer->accept(rv);
renderable->render();
// renderable = 0 -> seg-fault

还是只是我的实施错误?

是的,您似乎需要双重调度技术,它可以通过应用访客模式来实现。说明这个想法的代码:

接口部分:

class SimulationObject {
public:
    virtual void Accept(RenderableVisitor* visitor) const = 0;
    ...
};
class RenderableVisitor {
public:
    virtual void Visit(Pointer* pointer) const = 0;
    virtual void Visit(Particle* particle) const = 0;
    virtual void Visit(LearningObserver* learning_observer) const = 0;
}

具体部分:

class Pointer : public SimulationObject {
public:
    virtual void Accept(RenderableVisitor* visitor) const
    {
        visitor->Visit(this);
    }
};
class Particle : public SimulationObject {
public:
    virtual void Accept(RenderableVisitor* visitor) const
    {
        visitor->Visit(this);
    }
};
class LearningObserver : public SimulationObject {
public:
    virtual void Accept(RenderableVisitor* visitor) const
    {
        visitor->Visit(this);
    }
};
class ConcreteRenderableVisitor : public RenderableVisitor {
public:
    virtual void Visit(Pointer* pointer) const
    {
        std::cout << "Render a pointer" << std::endl;
    }
    virtual void Visit(Particle* particle) const
    {
        std::cout << "Render a particle" << std::endl;
    }
    virtual void Visit(LearningObserver* learning_observer) const
    {
        std::cout << "Render a learning observer" << std::endl;
    }
}

ConcreteRenderableVisitor类为类层次结构的每个叶实现逻辑SimulationObject

客户端代码:

ConcreteRenderableVisitor visitor;
Particle particle;
particle.Accept(&visitor); // Render a particle by the visitor.

客户端代码 2(更抽象的示例来证明该技术):

RenderableVisitor* visitor = new ConcreteRenderableVisitor;
SimulationObject* object = new Particle;
object->Accept(visitor);