2017-04-12 10 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 :

class std::shared_ptr<class Entity> 
class Person 
class std::shared_ptr<class Entity> 
class Bullet 
collided person with entity 
collided person with bullet 
: 약간 이상한 이유로
#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; 
} 

는 콘솔 다음 출력

그래서 엔티티 [1]이 클래스 글 머리 기호라는 것을 인식하는 것 같지만, 어떤 이유로 인해 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가 반환 한 포인터의 유효성을 검사해야합니다.