Вопрос:
Я пытался назначить указатель функции (класса) функции-члена (другого класса) следующим образом:
— Game.h — #ifndef GAME_H #define GAME_H #include «Screen.h» class Game { private: void (*HandleCurrentScreen)(); public: void SetScreen(const Screen& newScreen); }; #endif — Game.cpp — #include «Game.h» #include «Screen.h» void Game::SetScreen(const Screen& newScreen) { HandleCurrentScreen = newScreen.Handle; //Produces the error } — Screen.h — #ifndef SCREEN_H #define SCREEN_H class Screen { public: void Handle(); }; #endif — Screen.cpp — #include «Screen.h» void Screen::Handle() { … }
Я получаю эту ошибку:
ошибка C3867: “Экран :: Ручка”: список отсутствующих аргументов функции; use ‘& Screen :: Handle’ для создания указателя на элемент
Кажется, что это нормально, если HandleCurrentScreen указывает на функцию, которая также определена в классе Game. Я искал других людей с этой проблемой, но ни один из них, похоже, не был в таких случаях.
Решение, которое может работать, выглядит примерно так:
Screen* p_currentScreen; void Game::SetScreen(const Screen& newScreen) { p_currentScreen = &newScreen; }
а затем вместо вызова HandleCurrentScreen я могу вызвать p_currentScreen->Handle(), но для меня это кажется немного менее эффективным.
Что я могу сделать, чтобы исправить это? Должен ли я просто использовать указатель на класс вместо указателя на функцию?
Любые советы приветствуются.
Лучший ответ:
Ваша ошибка говорит вам, что делать:
Screen::Handle’: function call missing argument list; use ‘&Screen::Handle
Вы должны написать это как:
void Game::SetScreen(const Screen& newScreen) { HandleCurrentScreen = &Screen::Handle; }
Он будет работать только в том случае, если newScreen::handle является статической функцией. Но в этом случае вы можете инициализировать его во время компиляции. В противном случае HandleCurrentScreen должен быть указателем на функцию-член (PTMF), объявленную как:
void (Screen::*HandleCurrentScreen)();
Теперь, чтобы вызвать функцию из PTMF, вам нужен объект функции. Это делает ваше второе решение лучше.
Другим вариантом является std :: bind:
class Game { private: std::function<void()> HandleCurrentScreen; public: void SetScreen(const Screen& newScreen) { HandleCurrentScreen = std::bind(&Screen::Handle, &newScreen); } }; Ответ №1
std::bind создан для решения такой проблемы:
// — Game.h — #ifndef GAME_H #define GAME_H #include «Screen.h» #include <functional> class Game { private: std::function<void ()> HandleCurrentScreen; public: void SetScreen(const Screen& newScreen); }; #endif // — Game.cc — #include «Game.h» #include «Screen.h» void Game::SetScreen(const Screen& newScreen){ HandleCurrentScreen = std::bind( &Screen::Handle, newScreen); }
Однако, поскольку вашему Game классу нужна только функция, возможно, лучший дизайн, чтобы полностью исключить класс Screen из определения Game и передать его непосредственно:
#include <functional> class Game { public: typedef std::function<void ()> ScreenHandler; private: ScreenHandler HandleCurrentScreen; public: void SetHandle(const ScreenHandler &handle); }; #endif // — Game.cc — #include «Game.h» void Game::SetHandle(const ScreenHandler &handle){ HandleCurrentScreen = handle; }
Таким образом, у вас есть выбор для создания этого обработчика, как вы считаете нужным, без участия Game.