map — отображение двух типов объектов в переполнении стека

Я создаю небольшой фреймворк для симуляции в 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;
};

Теперь, когда в Simulation добавляется новый SimulationObject (во время выполнения), я хочу проверить, существует ли класс, который его отображает. Если так, я хочу создать экземпляр этого. Моей первой идеей было использовать полиморфность:

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, очевидно, не распознается как переопределение базового класса, но я надеялся, что с этот указывая на фактический (производный) тип, будет вызван правильный метод (метод MyRenderVisitor).

Мой тестовый сценарий выглядит так:

RenderVisitor * rv = new MyRenderVisitor();
SimulationObject * pointer = new Pointer();

Renderable * renderable = pointer->accept(rv);
renderable->render();
// renderable = 0 -> seg-fault

Или только моя реализация неверна?

1

Решение

Да, кажется, вам нужна техника двойной отправки, это можно реализовать, применив Шаблон посетителя.
Код для иллюстрации идеи:

Интерфейсная часть:

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);
1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector