【问题标题】:Strange behavior on overriding methods and calling them with shared_ptr覆盖方法并使用 shared_ptr 调用它们的奇怪行为
【发布时间】:2017-04-12 04:19:52
【问题描述】:

对于我的碰撞代码,我认为如果每个实体都覆盖并定义自己与任何其他实体的交互,那会很整洁。所以,我尝试实现这个:

Entity.h:

class Bullet;
class Person;
class Entity
{
public:
    Entity();
    ~Entity();
    virtual void resolveCollision(Entity &other);
    virtual void resolveCollision(Bullet &other);
    virtual void resolveCollision(Person &other);
};

Entity.cpp:

void Entity::Entity() {}
void Entity::~Entity() {}
void Entity::resolveCollision(Entity &other) {
    std::cout << "collided entity with entity" << std::endl;
}
void Entity::resolveCollision(Bullet &other) {
    std::cout << "collided entity with bullet" << std::endl;
}
void Entity::resolveCollision(Person &other) {
    std::cout << "collided entity with person" << std::endl;
}

Person.h:

#include "Entity.h"
class Person :
    public Entity
{
public:
    Person();
    ~Person();
    void resolveCollision(Entity &other) override;
    void resolveCollision(Bullet &other) override;
    void resolveCollision(Person &other) override;
};

Person.cpp:

Person::Person() {}
Person::~Person() {}

void Person::resolveCollision(Entity &other) {
    std::cout << "collided person with entity" << std::endl;
}
void Person::resolveCollision(Bullet &other) {
    std::cout << "collided person with bullet" << std::endl;
}
void Person::resolveCollision(Person &other) {
    std::cout << "collided person with person" << std::endl;
}

Bullet.h(几乎是 Person.h 的复制品):

#include "Entity.h"
class Bullet :
    public Entity
{
public:
    Bullet();
    ~Bullet();
    void resolveCollision(Entity &other) override;
    void resolveCollision(Bullet &other) override;
    void resolveCollision(Person &other) override;
};

Bullet.cpp(几乎是 Person.cpp 的复制品):

Bullet::Bullet() {}
Bullet::~Bullet() {}

void Bullet::resolveCollision(Entity &other) {
    std::cout << "collided bullet with entity" << std::endl;
}
void Bullet::resolveCollision(Bullet &other) {
    std::cout << "collided bullet with bullet" << std::endl;
}
void Bullet::resolveCollision(Person &other) {
    std::cout << "collided bullet with person" << std::endl;
}

最后是main.cpp:

#include "Bullet.h"
#include "Person.h"
#include <typeinfo>

int main()
{
    std::vector<std::shared_ptr<Entity>> entities;
    entities.push_back(std::shared_ptr<Person>(new Person()));
    entities.push_back(std::shared_ptr<Bullet>(new Bullet()));
    std::cout << typeid(entities[0]).name() << std::endl;
    std::cout << typeid(*entities[0]).name() << std::endl;
    std::cout << typeid(entities[1]).name() << std::endl;
    std::cout << typeid(*entities[1]).name() << std::endl;
    (*entities[0]).resolveCollision(*entities[1]);
    Person().resolveCollision(Bullet());
    return 0;
}

出于某种奇怪的原因,控制台输出以下内容:

class std::shared_ptr<class Entity>
class Person
class std::shared_ptr<class Entity>
class Bullet
collided person with entity
collided person with bullet

所以它似乎认识到 *entities[1] 是一个类 Bullet,但由于某种原因,它调用 Person::resolveCollision(Entity) 而不是 Person::resolveCollision(Bullet),即使创建了这些实例类和做同样的事情会输出玩家和子弹之间的碰撞。我在做什么导致这个?前向声明会导致这种情况吗?

谢谢!

【问题讨论】:

标签: c++ c++11 operator-overloading overriding shared-ptr


【解决方案1】:

电话

(*entities[0]).resolveCollision(*entities[1]);

在编译时解析为Entity::resolveCollision(Entity &amp;other);。借助virtual函数调度机制,调用在运行时被调度到Person::resolveCollision(Entity &amp;other);。但是,动态调度系统并没有根据other的运行时间信息改变对Person::resolveCollision(Bullet &amp;other);的调用。这需要double dispatch system,这不是语言的一部分。

【讨论】:

  • +1 用于删除或缺少双重调度机制,而不是引用关于如何在编译时解析虚拟函数调用的规范。
  • 除了尝试将每个子类动态转换为实体之外,还有其他解决方案吗?
  • @Matthew,你可以使用the visitor pattern,尽管我觉得它很讨厌。
【解决方案2】:

为了获得所需的行为,请使用以下代码:

auto bulletPtr = std::dynamic_pointer_cast<Bullet>(entities[1]);
if(bulletPtr)
{
    entities[0]->resolveCollision(bulletPtr);
}

entities[0] 的 resolvecollision 将调用 Person 的 resolveCollision,因为该函数是虚拟的并且在派生类中被覆盖。 c++ 运行时不知道entities[1] 实际上是一个bulletPtr,所以你必须动态地把它扔掉。您必须检查 dynamic_pointer_cast 返回的指针的有效性。

【讨论】:

    猜你喜欢
    • 2011-04-14
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    • 2017-10-24
    • 1970-01-01
    • 2022-01-23
    • 2021-06-09
    • 1970-01-01
    相关资源
    最近更新 更多