회원 기능 포인터를 어떻게 통과합니까?
문제
클래스 내의 멤버 함수를 멤버 함수 클래스 포인터를 취하는 함수로 전달하려고합니다. 내가 가진 문제는이 포인터를 사용하여 클래스 내에서 올바르게 수행하는 방법을 잘 모르겠다는 것입니다. 누구든지 제안이 있습니까?
회원 기능을 전달하는 클래스 사본은 다음과 같습니다.
class testMenu : public MenuScreen{
public:
bool draw;
MenuButton<testMenu> x;
testMenu():MenuScreen("testMenu"){
x.SetButton(100,100,TEXT("buttonNormal.png"),TEXT("buttonHover.png"),TEXT("buttonPressed.png"),100,40,&this->test2);
draw = false;
}
void test2(){
draw = true;
}
};
함수 X.SetButton (...)은 다른 클래스에 포함되어 있으며 "객체"는 템플릿입니다.
void SetButton(int xPos, int yPos, LPCWSTR normalFilePath, LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, int Width, int Height, void (object::*ButtonFunc)()) {
BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);
this->ButtonFunc = &ButtonFunc;
}
누구든지 나중에 사용할 수 있도록이 기능을 올바르게 보낼 수있는 방법에 대한 조언이 있다면.
해결책
포인터로 멤버 함수를 호출하려면 객체에 대한 포인터와 함수에 대한 포인터라는 두 가지가 필요합니다. 둘 다 필요합니다 MenuButton::SetButton()
template <class object>
void MenuButton::SetButton(int xPos, int yPos, LPCWSTR normalFilePath,
LPCWSTR hoverFilePath, LPCWSTR pressedFilePath,
int Width, int Height, object *ButtonObj, void (object::*ButtonFunc)())
{
BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);
this->ButtonObj = ButtonObj;
this->ButtonFunc = ButtonFunc;
}
그런 다음 두 포인터를 사용하여 기능을 호출 할 수 있습니다.
((ButtonObj)->*(ButtonFunc))();
포인터를 대상에 전달하는 것을 잊지 마십시오. MenuButton::SetButton()
:
testMenu::testMenu()
:MenuScreen("testMenu")
{
x.SetButton(100,100,TEXT("buttonNormal.png"), TEXT("buttonHover.png"),
TEXT("buttonPressed.png"), 100, 40, this, test2);
draw = false;
}
다른 팁
강하게 추천 할 것입니다 boost::bind
그리고 boost::function
이런 식으로.
나는 이것이 아주 오래된 주제라는 것을 알고 있습니다. 그러나 C ++ 11으로 이것을 처리하는 우아한 방법이 있습니다.
#include <functional>
이와 같이 기능 포인터를 선언하십시오
typedef std::function<int(int,int) > Max;
당신의 기능을 당신의 기능을 전달하십시오
void SetHandler(Max Handler);
정상적인 기능을 전달한다고 가정 해
SetHandler(&some function);
회원 기능이 있다고 가정 해 봅시다
class test{
public:
int GetMax(int a, int b);
...
}
코드에서 사용하여 전달할 수 있습니다 std::placeholders
이와 같이
test t;
Max Handler = std::bind(&test::GetMax,&t,std::placeholders::_1,std::placeholders::_2);
some object.SetHandler(Handler);
표준 OO를 사용하는 것이 더 좋지 않습니까? 계약 (가상 클래스)을 정의하고 자신의 클래스에서이를 구현 한 다음 자신의 클래스에 대한 참조를 전달하고 수신자가 계약 기능을 호출하도록하십시오.
예제를 사용합니다 ( 'test2'메소드의 이름이 'buttonAction')) : :
class ButtonContract
{
public:
virtual void buttonAction();
}
class testMenu : public MenuScreen, public virtual ButtonContract
{
public:
bool draw;
MenuButton<testMenu> x;
testMenu():MenuScreen("testMenu")
{
x.SetButton(100,100,TEXT("buttonNormal.png"),
TEXT("buttonHover.png"),
TEXT("buttonPressed.png"),
100, 40, &this);
draw = false;
}
//Implementation of the ButtonContract method!
void buttonAction()
{
draw = true;
}
};
수신기 메소드에서는 버튼 계정에 대한 참조를 저장 한 다음 버튼의 동작을 수행하려면 저장된 ButtonContract 객체의 'ButtonAction'메소드를 호출하십시오.
드문 경우 Borland C ++ Builder와 함께 개발 중이며 해당 개발 환경 (즉, 다른 C ++ 컴파일러와 작동하지 않는 코드)에 맞는 코드를 작성하는 것이 마음에 들지 않습니다. __closure 키워드를 사용할 수 있습니다. . 나는 a를 찾았다 C ++ 빌더 폐쇄에 관한 작은 기사. 그들은 주로 Borland VCl과 함께 사용하기위한 것입니다.
다른 사람들은 당신에게 그것을 올바르게하는 방법을 당신에게 말했습니다. 하지만 아무도이 코드가 실제로 위험하다고 말하지 않았다는 것에 놀랐습니다.
this->ButtonFunc = &ButtonFunc;
ButtonFunc은 매개 변수이므로 함수가 반환 될 때 범위를 벗어납니다. 당신은 주소를 취하고 있습니다. 당신은 유형의 값을 얻게됩니다 void (object::**ButtonFunc)()
(멤버 함수에 대한 포인터에 대한 포인터) 그리고이-> buttonfunc에 할당하십시오. 이-> buttonfunc을 사용하려고 할 때 (이제 더 이상 존재하지 않는) 로컬 매개 변수의 저장에 액세스하려고하면 프로그램이 충돌 할 것입니다.
나는 Commodore의 솔루션에 동의합니다. 그러나 당신은 그의 선을 바꿔야합니다
((ButtonObj)->*(ButtonFunc))();
buttonobj는 a 바늘 반대하다.