2015-08-24 5 views
0

У меня есть некоторые проблемы с пониманием указателей функций. Хотя я прочитал много тем, я все еще испытываю проблемы с последующим случаем.КАК: Указатели функций класса (C++)

Мой пример прост - у меня есть класс джойстика, который имеет некоторые указатели на функции, а также функции, с помощью которых эти указатели могут быть назначены, и я не знаю, как это сделать должным образом.

Постараюсь держать его просто:

class Joystick { 
    void (Player::*OnShootKeyPressed)(); // pointer that takes no arguments and returns nothing 

    void SetCallback(void (Player::*f)) { 
     OnShotKeyPressed = f; 
    } 
} 

class Player { 
    void OnShootAction() { ...do the shooting...} 

    void Initialize() { 
     Joystick* joy = pInputMng->GetJoystick(); 

     joy->SetCallback(&Player::OnShootAction()); 
    } 
} 

--Edited после капитана Obvlious comment--

Это один небольшой пример того, что я хочу достичь, и я не похоже, правильно понимают эти указатели функций. Что я делаю не так?

Я ценю всю помощь заранее!

+1

Вы не можете передать указатель на функцию-член как указатель на функцию, они не одно и то же. FWIW - синтаксис '& Player :: OnShootAction' не' & OnShootAction() '. –

+1

Пройдите через этот https://isocpp.org/wiki/faq/pointers-to-members. – user4581301

+0

Спасибо @CaptainObvlious, но я до сих пор не могу заставить его работать. – Blodyavenger

ответ

0

ИСПРАВЛЕНО КОД & ОТВЕТ

1.) у меня были некоторые проблемы с пространствами имен, не упомянутых в этом вопросе, так что я не был в состоянии создать функцию.

Оба класса находится под пространством имен, так что функция для назначения указателя функции была отклонена:

void      SetCallback(void (ehJoystick::*f)()) 

Он должен был быть вместо этого:

void      SetCallback(void (eg::ehJoystick::*f)()) 

Но тогда компилятор не сделал принять пространство имён. Я думал, что я делаю что-то неправильно в другом месте, но проблема там была все время.

2.) Я не знал, что вам нужна ссылка на объект, где вы хотите вызвать указатель на функцию-член. Следующий код правильный и работает.

class Joystick { 
    Player* pPlayer; 
    void (Player::*OnShootKeyPressed)() = NULL; // pointer that takes no arguments and returns nothing 

    void SetCallback(void (Player::*f)(), Player *p) { 
     OnShotKeyPressed = f; 
     pPlayer = p; // we need a reference to the object 
    } 
    void OnKeyPressed(key) { 
     if(key == SHOOT && OnShootKeyPressed != NULL) { 
      (pPlayer->*OnShootKeyPressed)(); //that's how the function is called 
     } 
    } 

class Player { 
    void OnShootAction() { ...do the shooting...} 

    void Initialize() { 
    Joystick* joy = pInputMng->GetJoystick(); 

    joy->SetCallback(&Player::OnShootAction, this); 
} 
+1

'& Player :: OnShootAction()' недействителен, это должно быть '& Player :: OnShootAction' –

+0

Вам также нужно предусмотреть' class Player; 'перед вашим' class Joystick {...} 'определение, если вы еще этого не сделали –

+0

Спасибо за исправление и да, класс игрока должен быть предварительно объявлен. – Blodyavenger

1

Я люблю указатели функций. Я считаю их среди моих лучших личных друзей. Но это, вероятно, не время для них. Когда у вас есть целые объекты, вызывающие друг друга взад и вперед, просто передайте объект.

Если вам нужно больше развязки между объектами, постройте интерфейс. Я поеду с интерфейсом, потому что почему бы и нет? Как только вы увидели трудный путь, легкий путь прост.

Во-первых, определить интерфейс для пользователей джойстика

class ButtonUser 
{ 
    virtual void OnShootAction() = 0; // function to be implemented by children 
    virtual void OnJumpAction() = 0; 
    virtual void OnDeathBlossomAction() = 0; 
    ... 
} 

Теперь джойстик, который использует интерфейс кнопки и абсолютно ничего не знает об игроке

class Joystick { 
    ButtonUser * pUser; 

    void SetCallback(ButtonUser * puser) { 
     pUser = puser; 
    } 
    void OnKeyPressed(key) { 
     if (pUser != NULL) { 
      switch(key) { 
       case SHOOT: 
        pUser->OnShootAction(); 
        break; 
       case JUMP: 
        pUser->OnjumpAction(); 
        break; 
       case DB: 
        pUser->OnDeathBlossomAction(); 
        break; 
       ... 
      } 
     } 
    } 
} 

И Игрок устанавливает себя в качестве пользователя джойстика

class Player: public ButtonUser{ 
    void OnShootAction() { ...do the shooting...} 
    void OnJumpAction() {...jump...}; 
    void OnDeathBlossomAction() {...blow $#!+ up!...} 
    ... 

    void Initialize() { 
    Joystick* joy = pInputMng->GetJoystick(); 

    joy->SetCallback(this); 
} 
+0

На самом деле это действительно хорошее решение и даже намного более чистым. Теперь я заменю код указателей на эту функцию. Ура! – Blodyavenger