gpt4 book ai didi

c++ - 使同质容器中的派生类彼此不同地交互

转载 作者:太空宇宙 更新时间:2023-11-04 13:35:23 25 4
gpt4 key购买 nike

当我不得不处理多态时,我在编写推箱子游戏时遇到了一个意想不到的问题。这是我简化的类层次结构:

#include <iostream>
#include <vector>
#include <memory>

using namespace std;

class GameObject
{
public:
virtual void onContact(GameObject* otherObject)
{
cout << "object met object" << endl;
}
};

class Crate;
class Wall;
class Hero;

class Crate: public GameObject
{
public:
virtual void onContact(Wall* w)
{
cout << "crate met wall" << endl;
}
virtual void onContact(Hero* h)
{
cout << "crate met hero" << endl;
}
};

class Wall: public GameObject
{
public:
virtual void onContact(Crate* c)
{
cout << "wall met crate" << endl;
}
virtual void onContact(Hero* h)
{
cout << "wall met hero" << endl;
}
};


class Hero: public GameObject
{
public:
virtual void onContact(Crate* crate)
{
cout << "hero met crate" << endl;
}
virtual void onContact(Wall* w)
{
cout << "hero met wall" << endl;
}
};

int main()
{
//Works
auto hero = unique_ptr<Hero>(new Hero());
auto crate = unique_ptr<Crate>(new Crate());
auto wall = unique_ptr<Wall>(new Wall());

hero->onContact(crate.get()); // "hero met crate"
hero->onContact(wall.get()); // "hero met wall"
crate->onContact(wall.get()); // "crate met wall"
wall->onContact(crate.get()); // "wall met crate"

cout << endl;

//Problem: in the program the game objects are stored in a vector (homogeneous container)
vector<unique_ptr<GameObject>> gameObjects;
gameObjects.push_back(move(hero));
gameObjects.push_back(move(crate));
gameObjects.push_back(move(wall));

/*
"object met object".
Should be "hero met crate".
That's because all objects in vector are GameObject.
*/
gameObjects[0]->onContact(gameObjects[1].get());

/* "object met object", should be "wall met crate" */
gameObjects[2]->onContact(gameObjects[1].get());

return 0;
}

所以这是我的问题/问题:由于大多数(所有?)STL 容器是同类的,所有派生对象都存储为基础对象(在我的例子中是 GameObject),因此根据参数的类型阻碍了适当的多态性联系方式。

如何在不动态转换(并检查有效的方法)的情况下恢复到原始类型?类设计有缺陷吗?

感谢您的帮助。

TL;DR:如何在派生对象的同质集合中优雅地应用多态性,这些对象以不同的方式相互交互?

要点:https://gist.github.com/gaultier/e437877395b5831a0623

最佳答案

您需要某种双重调度机制。一种可能性是使用访问者模式在两个对象的运行时类型上分派(dispatch)你的碰撞器。

将默认行为放入基类:

class GameObject
{
public:
virtual void contactHandlerDefault(GameObject* otherObject)
{
cout << "met an other object";
}

virtual void contactHandlerCrate(Crate* o);
virtual void contactHandlerWall(Wall* o);
virtual void contactHandlerHero(Hero* o);

virtual void onContact(GameObject* otherObject)
{
otherObject->contactHandlerDefault(this);
}
};

然后对于您的每个派生类,覆盖您想要的任何碰撞处理程序,然后让它们将它们的 this 指针转换为正确的静态类型,并将它们自己转发给碰撞对象中的正确处理程序:

class Hero: public GameObject
{
public:
virtual void onContact(GameObject* otherObject) override
{
otherObject->contactHandlerHero(static_cast<Hero*>(this));
}

virtual void contactHandlerDefault(GameObject* obj) override
{
cout << "do nothing, I can't go through";
}

virtual void contactHandlerCrate(Crate* crate) override
{
cout << "pushing the crate";
}
};

然后使基类处理程序转发到默认处理程序(您可以通过重载来完成此操作,这意味着您不需要这样做,但是如果您添加新类并且不这样做,则会出现编译错误'将处理程序添加到它):

void GameObject::contactHandlerCrate(Crate* o)
{
contactHandlerDefault(o);
}
//...

现在调用 gameObjects[1]->onContact(gameObjects[0]); 输出 pushing the crate。请注意,此方法意味着您需要反转调用,因此您调用的不是 hero->onContact(crate),而是调用 crate->onContact(hero)

关于c++ - 使同质容器中的派生类彼此不同地交互,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29744506/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com