2009-06-16 2 views
34

일부 처리를 사용자 정의하기 위해 콜백 함수를 등록해야하는 C 라이브러리가 있습니다. 콜백 함수의 유형은 int a(int *, int *)입니다.C++ 클래스 멤버 함수를 C 콜백 함수로 사용

나는 콜백 함수로 다음과 C를 등록하려고 ++ 클래스 함수와 유사 C++ 코드를 작성하고 있습니다 :

In constructor 'A::A()', 
error: 
argument of type ‘int (A::)(int*, int*)’ does not match ‘int (*)(int*, int*)’. 

내 질문 :

class A { 
    public: 
    A(); 
    ~A(); 
    int e(int *k, int *j); 
}; 

A::A() 
{ 
    register_with_library(e) 
} 

int 
A::e(int *k, int *e) 
{ 
    return 0; 
} 

A::~A() 
{ 

} 

컴파일러는 오류 다음 발생

  1. 우선 내가하려고하는 것처럼 C++ 클래스 멤버 함수를 등록 할 수 있으며, 그렇다면 h 오우? (나는 http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html에서 32.8을 읽었지 만 제 생각에는 문제가 해결되지 않습니다)
  2. 대체 방법/더 좋은 방법이 있습니까?

답변

37

회원 기능이 정적 일 때 가능합니다.

클래스 A의 비 정적 멤버 함수는 class A* 유형의 암시 적 첫 번째 매개 변수를 가지며 포인터에 해당합니다. 따라서 콜백의 서명에도 class A* 유형의 첫 번째 매개 변수가있는 경우에만 등록 할 수 있습니다.

+0

예. 그 해결책이 효과가있었습니다. 컴파일러가 오류를 표시하지 않는다는 것이 혼란 스럽습니다. int (A ::, int *, int *) 'int() (int, int *)' – Methos

+0

과 일치하지 않습니다. A : :)는 함수가 클래스 A의 일부이고, 거기에서 'this'포인터를 의미한다는 것을 의미합니다. – GManNickG

+0

난 궁금해서 ... 표준에 명시되어 있니? 방금 수업을 훑어 보았지만 찾지 못했습니다. 그럼에도 불구하고, 매우 흥미 롭습니다. 모든 컴파일러가 반드시 비 정적 멤버 함수를 이런 방식으로 처리해야한다고 생각하지 않습니다. – Tom

1

멤버 함수를 사용할 때의 문제는 행동 할 개체가 필요하다는 것입니다. C는 개체에 대해 알지 못합니다.

가장 쉬운 방법은 다음을 수행하는 것입니다!

//In a header file: 
extern "C" int e(int * k, int * e); 

//In your implementation: 
int e(int * k, int * e) { return 0; } 
+0

그래서 회원 기능을 수행하지 마십시오. – Methos

+0

이 경우 예. IMO는 독립형 기능을 사용함으로써 제공되는 단순성이 캡슐화가 부족하다는 것을 능가합니다. – PaulJWilliams

7

문제는 그 방법 = 기능입니다. 컴파일러는 그런 일에 당신의 방법을 변형시킬 것이다 : 클래스의 인스턴스가 인수로 전달 될 수 없기 때문에

int e(A *this, int *k, int *j); 

그래서, 그것은, 당신이 그것을 통과 할 수 있는지 확인합니다. 해결 방법 중 하나는 메서드를 정적으로 만드는 것입니다. 이렇게하면 좋은 형식이됩니다. 그러나 어떤 클래스 인스턴스도 아닌 정적 클래스 멤버에 대한 액세스도 아닙니다.

다른 방법은 처음으로 초기화 된 A에 대한 정적 포인터가있는 함수를 선언하는 것입니다. 이 함수는 클래스로만 호출을 리디렉션합니다.

int callback(int *j, int *k) 
{ 
    static A *obj = new A(); 
    a->(j, k); 
} 

그런 다음 콜백 함수를 등록 할 수 있습니다. 당신은 Win32 플랫폼에있는 경우

5

은 음 ...

Thunking in Win32: Simplifying callbacks to non-static member functions

그것은 솔루션입니다하지만 난 그것을 사용하지 않는 것이 좋습니다 ... 항상 불쾌한 썽킹 방법이있다.
좋은 설명이 있으며 그것이 존재한다는 것을 아는 것이 좋습니다.

는 멤버 함수가 정적 아니지만, 조금 더 많은 작업을 필요로하는 경우 당신은이 작업을 수행 할 수 있습니다
13

(또한 Convert C++ function pointer to c function pointer 참조) :

#include <stdio.h> 
#include <functional> 

template <typename T> 
struct Callback; 

template <typename Ret, typename... Params> 
struct Callback<Ret(Params...)> { 
    template <typename... Args> 
    static Ret callback(Args... args) {      
     func(args...); 
    } 
    static std::function<Ret(Params...)> func; 
}; 

template <typename Ret, typename... Params> 
std::function<Ret(Params...)> Callback<Ret(Params...)>::func; 

void register_with_library(int (*func)(int *k, int *e)) { 
    int x = 0, y = 1; 
    int o = func(&x, &y); 
    printf("Value: %i\n", o); 
} 

class A { 
    public: 
     A(); 
     ~A(); 
     int e(int *k, int *j); 
}; 

typedef int (*callback_t)(int*,int*); 

A::A() { 
    Callback<int(int*,int*)>::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2); 
    callback_t func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);  
    register_with_library(func);  
} 

int A::e(int *k, int *j) { 
    return *k - *j; 
} 

A::~A() { } 

int main() { 
    A a; 
} 

이 예제는 컴파일 있다는 점에서 완료 :

g++ test.cpp -std=c++11 -o test 

c++11 플래그가 필요합니다. 코드에서 register_with_library(func)이 호출 된 것을 볼 수 있습니다. 여기서 func은 동적으로 멤버 함수 e에 바인딩 된 정적 함수입니다.

+0

쿨! 나는 항상 이것을하는 방법을 알고 싶었다. – Jacko

+0

C 콜백 형식이 int __stdcall 콜백 (int *, int *) 형식 인 경우? – Jacko

+0

@ Jacko. 음 ... 그게 호출 수신자/호출자가 스택 정리를 담당한다는 것입니까? 나도 몰라 ... 나는 윈도우에 관한 모든 것을 잊어 버렸다. :-) –

관련 문제