2013-06-06 1 views
5

Nie jestem zbyt dobry w C++ (ale znam już OOP/Java), ale muszę stworzyć grę dla mojej klasy C++. Chcę ustawić rodzaj silnika gry takiego, jaki jest używany w grach Flash napisanych w języku ActionScript.C++ - Polimorficzny wskaźnik do funkcji składowych

Napisałem to dwie klasy, gdzie Actor rozumie się jako klasa bazowej (prawdopodobnie będzie streszczenie) i Player powinny rzeczywiście wdrożyć.

Problemem jest to, że chcę, aby uniknąć powielania kodu w funkcji addEventListener i handle i re-deklarujących _handlerMap, ponieważ chcę osiągnąć ukrywania danych i takie rzeczy.

Problem, domyślam się, że _eventMap powinien zawierać wartości handler, które mogą zmienić klasę Actor::*handler i Player::*handler. Czy to możliwe?

class Actor { 
    protected: 
     typedef void(Actor::*handler)(Event); 
     map<int, handler> _handlerMap; 
    public: 
     virtual void addEventListener(int ID, handler h) { 
      _handlerMap.insert(std::make_pair(ID, h)); 
     }; 
     virtual void handle(int ID) { 
      handler h = _handlerMap[ID]; 
      Event e; 
      if (h) 
       (this->*h)(e); 
     } 
     virtual void onUpdate(Event e) { 
      cout << "Actor::onUpdate()" << endl; 
     }; 
    }; 

class Player : public Actor { 
    typedef void(Player::*handler)(Event); 
    map<int, handler> _handlerMap; 
public: 
    void addEventListener(int ID, handler h) { 
     _handlerMap.insert(std::make_pair(ID, h)); 
    }; 
    void handle(int ID) { 
     handler h = _handlerMap[ID]; 
     Event e; 
     if (h) 
      (this->*h)(e); 
    } 
    void onKeydown(Event e) { 
     cout << "Player::onKeyDown()" << endl; 
    }; 
}; 

życzę można było zadeklarować odtwarzacza jak:

class Player : public Actor { 
     typedef void(Player::*handler)(Event); 
public: 
     void onWhateverEvent(Event e); 
} 

Mam nadzieję, że rozumiesz.

+0

Czy chcesz zezwolić na inne instancje 'Actor' zarejestrować obsługi? (tzn. czy 'addEventListener' musi być członkiem publicznym?) – dyp

+0

" Problem, jak sądzę, polega na tym, że '_ventMap'" -> masz na myśli '_handlerMap'? – dyp

+1

Najprostszym rozwiązaniem, jakie mogę sobie wyobrazić, jest użycie 'std :: function' oraz' std :: bind', dostępnych w C++ 11. – dyp

Odpowiedz

2

Trzeba coś takiego (nie sprawdzone)

class Dispatcher { 
    public: 
    virtual void dispatchEvent(Event*) = 0; 
}; 

template <class C> 
class DispatcherImpl : public Dispatcher 
{ 
    typedef void(C::*handler)(Event* e); 
    std::map<int, handler> _handlerMap; 
    C* _owner; 
    public: 
    DispatcherImpl (C* c) : _owner(c) {} 
    addEventListener(int ID, handler h) { 
     _handlerMap.insert(std::make_pair(ID, h)); 
    }   
    void dispatchEvent(Event*) 
    { 
     handler h = handlerMap[e->id]; 
     if (h) (_owner->*h)(e); 
    } 
} 

Teraz niech każdy rodzaj T aktora właścicielem DispatcherImpl<T> i wszystko jest gotowe. Możesz także mieć np. Player dziedziczy po DispatcherImpl<Player>.

+0

'dispatchEvent' musi zwrócić coś w celu np. Niech 'Player' przekaże wydarzenie" Aktorowi "na wypadek, gdyby nie było specjalnego programu obsługi w' Gracz' dla tego wydarzenia. Dodatkowo wolałbym użyć 'map :: find' zamiast' map :: operator [] ', aby sprawdzić, czy element istnieje na mapie. – dyp

+0

@DyP: absolutnie nie. "Gracz" * to * "Aktor". Do jakiego innego "aktora" chcesz przejść? Jeśli chodzi o 'map :: find', z pewnością używaj go. Ten fragment jest ściśle pseudokodowy, nie można go używać dosłownie. –

+0

Masz na myśli, że tylko typy pochodne powinny dziedziczyć po 'DispatcherImpl'? Myślałem, że masz na myśli także "Aktor", który powinien z tego czerpać; w takim przypadku musiałbyś zwrócić np. 'bool' z' dispatchEvent' w celu wskazania, czy identyfikator zdarzenia został znaleziony w bieżącej '_handlerMap' lub czy powinien zostać przekazany do dyspozytora klasy podstawowej, który ma być obsługiwany. – dyp

0

Co o tym sądzisz? (Dyspozytor jest taka sama jak DispatcherImpl powyżej)

template <class T> 
class Entity { 
    T *_instance; 
    Dispatcher<T> *_dispatcher; 
public: 
    Entity() { 
     _instance = new T(); 
     _dispatcher = new Dispatcher<T>(_instance); 
    } 
}; 
class Actor { 
    //attirbutes and methods 
}; 
class Player : public Actor { 
    //attirbutes and methods 
}; 

Aby go użyć tylko:

Entity<Actor> *actor = new Entity<Actor>(); 
Entity<Player> *player = new Entity<Player>(); 
actor->getDispatcher()->addEventListener(0, &Actor::foo); 
player->getDispatcher()->addEventListener(1, &Player::bar); 
player->getDispatcher()->addEventListener(0, &Actor::foo); //inheritance