함수포인터 - 콜백(callback) (펌)

2015. 10. 20. 15:02IT-개발/C및C++

반응형

함수포인터 

(출처 : http://igotit.tistory.com/entry/%ED%95%A8%EC%88%98%ED%8F%AC%EC%9D%B8%ED%84%B0-%EC%BD%9C%EB%B0%B1Callback)

 

 

1. int Function(int a) {... } ; 로 정의된  함수가 있다치자.

 

2. 위 1의 함수의 포인터(함수이름이 포인터임)를 받을 수 있는 함수포인트 변수 선언하고 1의 함수포인터를 대입하는 방법 

 int (*pFunc)(int) = Function; 

 

3. 2처럼 대입하고나서, pFunc(1); 이라고 호출하면 Function(1); 이 호출되는 것임.

 

4. 1의 함수를  다른 함수 "myfunc" 의 입력인자 로 전달하기 위한 다른 함수 "myfunc" 정의 방법.

void myfunc( int (*pFunc)(int) )

{

   pFunc(1);

}

myfunc 호출시 상기1의 함수를 인자로 전달하는 법 : myfunc(Function);

 

5. 상기2와 같은 함수포인터 변수를 사용자 타입정의하는 법..

typedef int(*pFunc)(int);

 

6. 상기 5에서 선언된 타입으로 변수 선언하는법.

pFunc my_pfunc1;

pFunc my_pfunc2;

 

7. 상기 5에서의 사용자 정의 타입으로 상기 4의 함수포인터 전달하는 인자 부분 변경하면,

 

void myfunc( pFunc p_func )

{

p_func(1);

}

mufunc 호출시 상기1의 함수를 인자로 전달하는 법 : myfunc(Function);

 

콜백개념

 

 

8. "이곳"에 있는 함수를 다른곳(예.  다른 클래스 개체, DLL등 )에 전달하여 다른 곳에서 "이곳"의 함수를 호출하는 법 <- 이런걸 콜백이라 부름.

"다른 곳"으로 "이 곳"의 함수를 전달하고 "다른 곳"에서 "이곳"의 함수를 호출하게 하는 것.

 

"다른 곳" 코딩.

 

typedef int(*pFunc)(int);

pFunc your_func;          // "이 곳"의 함수를 받을 함수포인터변수 선언이다.

 

//"이 곳"의 함수포인터로 인자를 전달하면 your_func 으로 대입해두는 함수.

void regi_func(pFunc p_func)

{

  your_func = p_func;  // 인자로 전달받은 함수포인터를 your_func 에 대입했다.

}

//

void exec_func()

{

 your_func(1);  // regi_func 의 인자로 전달된 함수가 실행되는 것임.

}

 

"이곳 " 코딩.

이곳에는 int Function(int a) {... } 함수가 정의되어있는데 이 함수를 "다른 곳" 의 regi_func 을 호출하면서 함수포인터를 전달한다.

regi_func(Function);

 

작동방식 요약.- 콜백 작동 개념임.

위와 같이 Function 이라는 함수포인터는  "다른곳" 의 regi_func 의 인자로 전달하여 "다른곳"의 your_func 에 대입된다..  exec_func 실행될때 your_func 가 실행되는데 이것이 실제 실행되는 것은 "이곳"의 Function(1) 이 실행된 것이다.

 

 

주의사항.

- 위와같은 함수포인터 기반의 콜백구현시 "이곳"측의 함수는 클래스의 멤버함수를 전달하지 못하며, 클래스에서 static 함수만 전달가능한 단점이 있다.

static 함수이다 보니 함수내에서 클래스 멤버에 접근하지 못하여 불편한 경우가 자주 발생한다. static 함수내에서 클래스 멤버에 접근하지 않아도 되는 경우는 문제없이 사용가능하나, 범용적이지 못한 방법이라 콜백 구현하는 경우 위와 같은 함수 포인터 보다는 STL(Standard Template Library) 에서 제공하는 std::function, std::bind 를 이용하여 콜백구현하면 클래스 멤버 함수를 콜백함수로 구현가능하여 매우 편리하다.

STL 기반 콜백구현 상세설명 보기 -> http://igotit.tistory.com/213


개요 


통상 콜백함수 구현시  함수포인터 기반으로 구현하는 방식 (보기 -> http://igotit.tistory.com/212 ) 으로는 클래스 멤버함수를 콜백으로 등록하지 못하는 단점이 있다. 


STL (Standard Template Library) 에서 제공하는 std::function, std::bind 등을 사용하면 클래스 멤버함수도 콜백함수로 등록가능하므로 대단히 편리하다. 

 

STL 기반 콜백구현방법 


아래 설명방식에서 "다른 곳", "이곳" 이란 표현은 함수포인터 기반 콜백구현방법 설명글 (http://igotit.tistory.com/212 )에서의 것과 동일한 것임.


 "이곳"에 있는 함수(클래스의 멤버함수도 가능하다.)를 다른곳(예.  다른 클래스 개체, DLL등 )에 전달하여 다른 곳에서 "이곳"의 클래스 멤버 함수를 호출하는 법에 대한 STL 기반 코딩 골격을 정리한다.  

"다른 곳" 코딩. - 아래 파란색 부분이 STL기반 구현부분 핵심에 해당함.


#include <functional> // std::functional 등을 사용하기 위하여 포함함.


typedef std::function<int(int)> pFunc; // pFunc 이라는 타입선언. 이것은 함수포인터 방식에서의 typedef int(*pFunc)(int); 에 해당함.


pFunc your_func;          // "이 곳"의 함수를 받을 변수선언이다. 함수포인터 방식에서와 동일함.  

 


//"이 곳"의 함수포인터로 인자를 전달하면 your_func 으로 대입해 줄 함수.


void regi_func(pFunc p_func)


{


  your_func = std::move(p_func);  //인자로 전달받은 함수포인터를 your_func 으로 받는다.함수포인터방식에서your_func = p_func에 해당.


}


// 


void exec_func()

{


 your_func(1);  // regi_func 의 인자로 전달된 함수가 실행되는 것임. 


}

 


"이곳 " 코딩. 


이곳에는 클래스 ThisClass 의 멤버 함수 int Function(int a) {... } 가  정의되어있다고 치자. 클래스 멤버함수를 "다른 곳" 의 regi_func 을 호출하면서 함수포인터를 전달한다. 


regi_func(std::bind(&ThisClass::Function, this, std::placeholders::_1));

 


// 클래스멤버함수 전달시 std::bind 를 사용한다는 점. 클래스의 this 개체 전달한다는 점, 클래스 멤버함수의 인자 1개 있다는점을 표현한것이다. 비교 : 함수포인터 방식에서는 regi_func(Function); 으로 했었다.


std::placeholder 관련처리 상세.


우리가 정의한 콜백함수 Function 에 만일 인자가 없다면 기록하지 않으면 된다. 만일 인자가 3개라면 즉 Function(int a, float b, char c) 라면 


위 등록함수는 아래처럼 인자수량만큼 추가하면 된다. 


regi_func(std::bind(&ThisClass::Function, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));


결론. 


위와 같이 설정해두면 , "다른곳" 의 exec_func() 이 실행되면 "이곳"의 클래스 멤버함수인 Function 이 실행된다. 


위 방식이 STL 기반 콜백함수 구현의 골격 전부이다. 이 방식으로 클래스 멤버함수도 간단히 콜백함수로 전달가능하여 콜백함수내에서 클래스 멤버에 접근이 용이하고 코드 구조도 간결해지는 큰 장점이 있다. 



'IT-개발 > C및C++' 카테고리의 다른 글

argv / argc 에 대해_1  (0) 2016.04.26
전처리문... 한번씩 참고 (펌)  (0) 2016.03.07
struct, class 키워드  (0) 2015.10.19
#pragma 사용법 정리  (0) 2015.09.30
extern - case1  (1) 2015.09.30