문제

다음과 같이 정의된 함수 포인터가 있습니다.

typedef void (*EventFunction)(int nEvent);

C++ 개체의 특정 인스턴스로 해당 함수를 처리할 수 있는 방법이 있습니까?

class A
{
private:
    EventFunction handler;

public:
    void SetEvent(EventFunction func) { handler = func; }

    void EventOne() { handler(1); }
};

class B
{
private:
    A a;
public:
    B() { a.SetEvent(EventFromA); }  // What do I do here?

    void EventFromA(int nEvent) { // do stuff }
};

편집하다: Orion은 Boost가 제공하는 다음과 같은 옵션을 지적했습니다.

boost::function<int (int)> f;
X x;
f = std::bind1st(
      std::mem_fun(&X::foo), &x);
f(5); // Call x.foo(5)

불행히도 Boost는 나에게 옵션이 아닙니다.멤버 함수에 대한 포인터를 일반 함수 포인터로 래핑하는 일종의 "커링" 함수가 C++로 작성될 수 있습니까?

도움이 되었습니까?

해결책

Don Clugston의 우수한 FastDelegate 라이브러리를 적극 권장합니다. 그것은 당신이 실제 대의원에 대해 기대할 모든 것을 제공하고 대부분의 경우 몇 가지 ASM 지침으로 컴파일합니다. 함께 제공되는 기사는 회원 기능 포인터에 대한 좋은 읽기입니다.

http://www.codeproject.com/kb/cpp/fastdelegate.aspx

다른 팁

기능 포인터를 사용하여 주어진 객체 인스턴스의 vtable에 색인 할 수 있습니다. 이것을 a라고합니다 멤버 기능 포인터. ".*"및 "& ::"연산자를 사용하려면 구문을 변경해야합니다.

class A;
class B;
typedef void (B::*EventFunction)(int nEvent)

그리고:

class A
{
private:
    EventFunction handler;

public:
    void SetEvent(EventFunction func) { handler = func; }

    void EventOne(B* delegate) { ((*delegate).*handler)(1); } // note: ".*"
};

class B
{
private:
    A a;
public:
    B() { a.SetEvent(&B::EventFromA); } // note: "&::"

    void EventFromA(int nEvent) { /* do stuff */ }
};

RAW C ++ 기능 포인터에서 멀어지고 사용합니다. std::function 대신에.

당신이 사용할 수있는 boost::function C ++ 11을 지원하지 않는 Visual Studio 2008과 같은 오래된 컴파일러를 사용하는 경우.
boost:function 그리고 std::function 같은 것입니다 - 그들은 C ++ 11을 위해 STD 라이브러리로 약간의 부스트 물건을 뽑았습니다.

참고 : 이해하기 쉽기 때문에 Microsoft 대신 Boost 기능 문서를 읽을 수 있습니다.

당신은 찾을 수 있습니다 Marshall Cline의 C ++ FAQ 성취하려는 것에 도움이됩니다.

에 대해 읽다 회원들에게 포인터. 파생 클래스에서 메소드를 호출하려면이 메소드는 기본 클래스에서 가상으로 선언되고 기본 클래스에서 재정의되어야하며 포인터는 기본 클래스 메소드를 가리켜 야합니다. 더 많은 것에 대해 가상 멤버에게 포인터.

C 라이브러리와 인터페이스하는 경우와 같은 것을 사용하지 않고 클래스 멤버 기능을 사용할 수 없습니다. boost::bind. 콜백 함수를 취하는 대부분의 C 라이브러리는 일반적으로 선택한 추가 인수 (보통 유형의 추가 인수를 전달할 수 있습니다. void*), 수업을 부트 스트랩하는 데 사용할 수 있습니다.


class C
{
public:
  int Method1(void) { return 3; }
  int Method2(void) { return x; }

  int x;
};

// This structure will hold a thunk to
struct CCallback
{
  C *obj;  // Instance to callback on
  int (C::*callback)(void);  // Class callback method, taking no arguments and returning int
};

int CBootstrapper(CCallback *pThunk)
{
  // Call the thunk
  return ((pThunk->obj) ->* (pThunk->callback))( /* args go here */ );
}

void DoIt(C *obj, int (C::*callback)(void))
{
  // foobar() is some C library function that takes a function which takes no arguments and returns int, and it also takes a void*, and we can't change it
  struct CCallback thunk = {obj, callback};
  foobar(&CBootstrapper, &thunk);
}

int main(void)
{
  C c;
  DoIt(&c, &C::Method1);  // Essentially calls foobar() with a callback of C::Method1 on c
  DoIt(&c, &C::Method2);  // Ditto for C::Method2
}

불행히도, 이벤트 기능 유형은 올바른 유형이 아니기 때문에 B의 함수를 가리킬 수 없습니다. 당신은 그것을 올바른 유형으로 만들 수 있지만 아마도 당신이 원하는 솔루션은 아닙니다.

typedef void (*B::EventFunction)(int nEvent);

... 그리고 나서 모든 것이 B의 홀로 콜백을 호출하면 모든 것이 작동합니다. 그러나 다른 일을하는 다른 클래스에서 B 이외의 기능을 호출 할 수 있기를 원할 것입니다. 그것은 일종의 콜백의 요점입니다. 그러나 이제이 유형은 B에서 확실히 무언가를 가리 킵니다. 더 매력적인 솔루션은 다음과 같습니다.

  • B를 기본 클래스로 만든 다음 호출 될 수있는 서로 클래스의 가상 함수를 대체하십시오. 그런 다음 A는 함수 포인터 대신 B에 포인터를 저장합니다. 훨씬 깨끗합니다.
  • 기능을 특정 클래스 유형, 심지어 기본 클래스 (그리고 나는 당신을 비난하지 않을 것입니다)에 바인딩하고 싶지 않다면 정적 함수라고 불리는 함수를 만드는 것이 좋습니다. "static void EventFrom A(int nEvent);". 그러면 B의 대상없이 직접 호출 할 수 있지만 B의 특정 인스턴스를 호출하기를 원할 것입니다 (B가 싱글 톤이 아니라면).
  • 따라서 B의 특정 인스턴스를 호출 할 수 있지만 비 B를 호출 할 수 있으려면 콜백 함수가 올바른 개체를 호출 할 수 있도록 다른 것을 콜백 함수로 전달해야합니다. 위와 같이 함수를 정적으로 만들고 B를 포인터로 만들 수있는 void* 매개 변수를 추가하십시오.

실제로이 문제에 대한 두 가지 솔루션이 있습니다 : 공허*와 이벤트를 통과하는 임시 시스템 및 Windowing Systems와 같은 기본 클래스에서 가상 기능을 갖춘 계층 구조

부스트는 옵션이 아니라고 말씀하셨는데 TR1을 사용할 수 있나요?

TR1은 부스트 ​​라이브러리를 기반으로 하는 함수, 바인드 및 mem_fn 개체를 제공하며 이미 컴파일러와 함께 번들로 제공되어 있을 수 있습니다.아직 표준은 아니지만 최근에 사용한 컴파일러 중 적어도 두 개에는 표준이 있었습니다.

http://en.wikipedia.org/wiki/Technical_Report_1
http://msdn.microsoft.com/en-us/library/bb982702.aspx

여기서 성취하려고하는 것이 다소 불분명합니다. 분명한 것은 기능 포인터가 방법이 아니라는 것입니다.

아마도 당신이 찾고있는 것은 방법에 대한 포인터 일 것입니다.

C ++ 프레임 워크에서 사용하는이 정확한 것을위한 클래스 세트가 있습니다.

http://code.google.com/p/kgui/source/browse/trunk/kgui.h

처리 방법 콜백으로 사용할 수있는 각 클래스 함수는 객체 유형을 바인딩하는 정적 함수가 필요합니다. 자동으로 수행하는 매크로 세트가 있습니다. "CB_"접두사와 클래스 객체 포인터 인 추가 첫 번째 매개 변수를 제외하고 동일한 이름의 정적 기능을 만듭니다.

다른 매개 변수 조합을 처리하기 위해 클래스 유형 KGUICALLBACK 및 다양한 템플릿 버전을 확인하십시오.

#define CALLBACKGLUE(classname , func) static void CB_ ## func(void *obj) {static_cast< classname *>(obj)->func();}
#define CALLBACKGLUEPTR(classname , func, type) static void CB_ ## func(void *obj,type *name) {static_cast< classname *>(obj)->func(name);}
#define CALLBACKGLUEPTRPTR(classname , func, type,type2) static void CB_ ## func(void *obj,type *name,type2 *name2) {static_cast< classname *>(obj)->func(name,name2);}
#define CALLBACKGLUEPTRPTRPTR(classname , func, type,type2,type3) static void CB_ ## func(void *obj,type *name,type2 *name2,type3 *name3) {static_cast< classname *>(obj)->func(name,name2,name3);}
#define CALLBACKGLUEVAL(classname , func, type) static void CB_ ## func(void *obj,type val) {static_cast< classname *>(obj)->func(val);}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top