C++中Double Dispatch失效问题排查求助
解决Roguelike游戏中Double Dispatch双分派失效的问题
你遇到的问题核心是双分派只完成了一半——你的代码里只触发了第一次动态绑定,第二次分派因为参数静态类型的限制没生效。咱们一步步拆解:
为什么当前代码没触发派生类逻辑?
当你用shared_ptr<MapObject>存储对象时,*cells[i][j][z+1]的静态类型是MapObject&,哪怕它实际是Wall或Player的实例。C++的重载决议是基于静态类型的,所以编译器会匹配collide(MapObject&)这个基类方法,而你这个方法是空实现,自然不会触发Wall或Player的特定逻辑。
双分派的关键是要完成两次动态绑定:
- 第一次:调用者的动态类型决定执行哪个
collide方法 - 第二次:参数的动态类型决定执行哪个重载版本
你现在缺的就是把第一次分派的结果转发给第二次分派的逻辑。
修复方案:补全基类的collide(MapObject&)转发逻辑
修改基类MapObject的collide(MapObject&)方法,让它完成第二次分派的转发:
class MapObject { virtual void collide(MapObject& that) { // 核心:让参数对象调用它的collide方法,传入当前对象(动态类型) that.collide(*this); }; virtual void collide(Player& that) {}; virtual void collide(Wall& that) {}; virtual void collide(Monster& that) {}; };
修复后的碰撞流程(以Player碰Wall为例)
当你执行cells[i][j][z]->collide(*cells[i][j][z+1])时:
- 假设
cells[i][j][z]是Player实例,第一次动态绑定调用Player继承的collide(MapObject& that)(也就是基类的转发方法) - 这个方法里调用
that.collide(*this),此时that是Wall实例,第二次动态绑定会调用Wall::collide(Player& that) Wall::collide(Player&)里调用that.collide(*this),也就是Player::collide(Wall& that),最终执行你的move_back逻辑
额外注意事项
- 避免循环调用:如果你的
Player::collide(Wall&)也调用that.collide(*this),就会无限循环。你的当前代码里Player的实现没有这么做,这是对的。 - 派生类按需重写:如果某个派生类需要处理和
MapObject基类的碰撞(比如通用逻辑),可以重写collide(MapObject&),否则直接继承基类的转发逻辑即可。 - 覆盖所有重载:确保每个派生类都实现了对应所有其他类型的
collide重载,避免遗漏导致触发基类空实现。
内容的提问来源于stack exchange,提问作者user7369463
相关产品推荐
相关产品推荐

