首先,我的代码的一个小解释,把上下文的问题:
我有一个类,负责在屏幕上绘制东西,我使用一个重载函数来绘制不同类型的可绘制实体,函数看起来像这样:
draw(entityType1* name);
draw(entityType2* name);
draw(entityType3* name);
...
所有实体类都派生自父“实体”类
我写了一个名为“Scene”的类,它有一个包含场景中所有可绘制对象的实体列表,我将该场景对象传递给负责在屏幕上绘制内容的类。
我们的想法是遍历列表并使用函数重载来绘制列表上不同类型的对象,但是由于列表只包含Entity类型的对象,因此我不能真正使用函数重载,因为它只适用于子类
我在找一个和这个类似的代码
void Painter::draw(Scene* scene) {
std::list<Entity*> drawables = scene->getDrawables();
for (auto it = drawables.begin(); it != drawables.end(); it++) {
draw(*it); //Should apply the correct overload
}
}
这段代码显然不起作用,因为我没有任何接受实体类型的draw()函数。我总是可以要求实体类型逐个执行,但这违背了使用重载函数的目的,也违反了“告诉,不要问”的原则。
我可能做了一些非常错误的事情,但我真的不知道如何进行,这就是为什么我问这个问题,我想知道什么是正确的方法来解决这个问题,同时尊重OOP原则,可能性是开放的,一切都在表上的变化我的代码。
先谢了
2条答案
按热度按时间gab6jxml1#
你可以使用访问者模式来解决这个问题,这个模式将函数调用委托给对象本身,所以你不需要使用对象的类型来调用正确的函数。
以下是您可以实现它的方法:
访问者模式的更高级实现可以在这里找到:Implementing the visitor pattern using C++ Templates
ua4mk5z42#
如果我没理解错你的问题,你想要的是在
Painter
类中有draw
的逻辑,而原始的Entity
类型保持不变。你可以通过类型擦除来实现这一点:它的本质是
DrawableEntityView
可以用Entity
的任何派生类来构造。这将在
e1_view
中存储一个Entity*
,而函数指针drawn_by_impl
将存储一个lambda,该lambda可以将p_entity
转换为基于构造它所使用的类型,并使用它调用Painter::draw
。现在你可以有这样的代码:
当然,您可以在
Painter
中添加一个成员函数,如下所示:现在在for循环中,可以有:
下面是一个演示:https://godbolt.org/z/fPM4nv3xz
我特意将其设为 view,但您也可以将
DrawableEntity::p_entity
设为所属指针,并删除一些常量。现在您可以让场景直接将实体存储为DrawableEntity
。