2009-09-04 3 views
5

C++로 작성된 사용자 정의 Menu 클래스가 있습니다. 코드를 읽기 쉬운 함수로 분리하기 위해 콜백을 사용하고 있습니다.C++에서 유용한 콜백을 구현하는 좋은 방법

Menu의 호스트에 Singletons를 사용하고 싶지 않기 때문에 콜백에 첫 번째 매개 변수 (누락 된 "this"참조에 대한 일종의 해결 방법)가 주어질 다른 매개 변수 (target) . Handler를

/* static */ 
void MyApp::OnModeSelected(void* that, MenuItem* item) { 
    MyApp *self = (MyApp*)that; 
    self->activeMode = item->text; 
} 

의 등록

menu->AddItem(TRANSLATE, "translate", &MyApp::OnModeSelected); 

예의

등록-서명

AddItem(string s, void(*callback)(void*,MenuItem*), void* target = NULL) 

예는 하나이 방법으로 더러운도 고려할 수 있습니다 무엇인가? 어쩌면 더 좋은 것들이 있을까요?

+0

당신은해야 여기서 정적 멤버 메서드를 콜백으로 사용하지 말고 extern "C"로 선언 된 함수 만 사용해야합니다. 사용중인 컴파일러가 (현재) 정적 메서드를 호출하는 데 같은 메서드를 사용한다는 것은 운이 좋았던 것입니다 그리고 기능이. 이것은 표준에 의해 보장되지 않습니다. –

답변

10

당신의 접근 방식은 콜백 함수가 자유 함수이거나 클래스의 정적 멤버가되어야합니다. 클라이언트가 멤버 함수를 콜백으로 사용할 수 없습니다.

menu->AddItem("Open", boost::bind(&MyClass::Open, this)); 

또 다른 옵션이 있습니다 boost::signals를 사용하는 것입니다 : 콜백에 전달하는

typedef boost::function<void (MenuItem*)> callback_type; 
AddItem(const std::string& s, const callback_type& callback = callback_type()); 

이 클라이언트는 다음 boost::bind 또는 boost::lambda을 사용할 수 있습니다 :이 문제를 해결하는 한 가지 방법은 콜백의 유형으로 boost::function을 사용하는 것입니다 동일한 이벤트에 대해 등록 할 다중 콜백.

+0

줄 'MenuItem &' 그러나 그렇지 않으면 전적으로 동의했다. – MSalters

+0

클래스의 정적 멤버를 일반 콜백으로 사용하면 안됩니다 (정의 된 ABI가 없음). boost :: 함수는 인터페이스 선언을 일반화 한 것입니다 (boost :: 함수는 인터페이스 연산자()를 사용합니다). 나는이 경우 좀 더 명시 적으로 인터페이스를 사용하여 orsogufo에 설명 된대로 부적절한 메소드를 다시 전달하지 않도록 (즉, 콜백의 유효성을 검사하는 컴파일러 가져 오기) 선호합니다. –

8

나는 귀하의 접근 방식을 좋아합니다. 하나 개의 대안은 콜백의 "OO에 해당"어떤 의미에서 인터페이스 선언하는 것입니다 : 등록 서명이

AddItem(string s, IMenuEntry * entry); 

그리고 메소드 구현 될 것

class IMenuEntry { 
public: 
    virtual void OnMenuEntrySelected(MenuItem* item) = 0; 
}; 

class MyApp : public IMenuEntry { 
public: 
    virtual void OnMenuEntrySelected(MenuItem* item){ 
     activeMode = item->text; 
    } 
} 

인터페이스 방식을 사용하면 누락 된 this 포인터에 대한 "무효 * 해결 방법"을 피할 수 있습니다.

1

함수 포인터 서명을 읽기가 어렵다는 점만 제외하면 나에게 잘못된 것이 없습니다. 하지만, 아마 observer 패턴을 달성 할 것입니다.

3

boost::bind을 사용해보세요.

menu->AddItem(TRANSLATE, 
       "translate", 
       boost::bind(&MyApp::OnModeSelected, this, _1, _2)); 
1

내가보기 엔 이것에 대한 boost::functionboost:bind보고 권 해드립니다. 그것을 배우면 당신의 기능 바인딩을 100 배 쉽게 할 수 있습니다.

+0

또한 부스트 :: lambda 잊지 마세요. 때로는 콜백없이 멀리 수 있습니다! – EFraim

+0

부스트 :: 신호이 작업에 더 좋습니다. – Arpegius

1

this 백서를 읽으십시오. 성능, 유용성 및 다른 절충안을 상당히 상세하게 분석하여 콜백 메커니즘을위한 다양한 기술을 구축합니다.나는 그것을 당신이 당신의 콜백을 캡슐화하는 functor을 사용할 수 :-(

0

하지만 하드 읽기를 발견했다. 이것은 당신이 C 스타일 함수 또는 콜백을 제공하는 객체 인터페이스를 사용하도록 허용합니다.

관련 문제