2017-04-12 6 views
2

私の衝突コードでは、各エンティティがオーバーライドされ、他のエンティティとの相互作用が定義されていればうまくいくと思いました。だから、私はこれを実装しようとした:メソッドをオーバーライドしてshared_ptrで呼び出す際の異常な動作

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(Bullet)ではなくPerson :: resolveCollision(Bullet)を呼び出します。同じことをすると、プレーヤーと弾丸の間に衝突が発生します。これを引き起こすために私は何をしていますか?フォワード宣言が原因ですか?

ありがとうございました!

+0

[C++のベースクラスへのポインタが与えられたときに派生クラスオブジェクトの関数がオーバーロードされないのはなぜですか?](http://stackoverflow.com/questions/22658316/why-is-not-overloaded-function -for-derived-class-object-invoked-when-given-a-poi) –

答えて

3

コール

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

は、コンパイル時にEntity::resolveCollision(Entity &other);に解決されます。 virtualファンクションディスパッチ機構によって、実行時にPerson::resolveCollision(Entity &other);にコールがディスパッチされます。しかし、動的ディスパッチシステムは、実行時間情報otherに基づいて、Person::resolveCollision(Bullet &other);への呼び出しを変更しません。それには言語の一部ではないdouble dispatch systemが必要です。

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

エンティティの機能は、仮想および派生クラスでオーバーライドされると、人のresolveCollisionを呼び出します[0]さんresolvecollision:希望の動作は以下のコードを使用して取得するためには

+1

+1コンパイル時に仮想関数呼び出しがどのように解決されるかについての仕様を引用するのではなく、 – BitTickler

+0

エンティティへのすべてのサブクラスに動的にキャストしようとする以外の解決策はありますか? – Matthew

+0

@Matthew、私はそれが嫌なことに気付いても、[訪問者のパターン](https://en.wikipedia.org/wiki/Visitor_pattern)を使用することができます。 –

0

。 C++の実行時には、エンティティ[1]が実際にはbulletPtrであることを示す手がかりがないため、ダイナミックにキャストする必要があります。 dynamic_pointer_castが返すポインタの有効性をチェックする必要があります。

関連する問題