함수의 주소를 저장해 함수를 가리키는 포인터이다.
예를 들어, int형 함수에 대한 함수포인터의 이름을 fP라고 하고 선언해보면
int (*fP)(); // 반환 값이 없을 때
int (*fP)(int); // int형을 반환할 때
이렇게 선언 할 수 있다.
int ( *fP ) 이렇게 괄호를 치는 이유는 우선순위 때문이다.
만약 int *fP로 선언해버리면 함수 포인터가 아니라
int형 포인터를 반환하는 함수가 되기 때문이다.
상수 함수 포인터를 사용한다면
int(* const fP)();
이런식으로 * 연산자 뒤에 const를 붙이면 된다.
const를 int앞에 붙이면 const int를 붙이는 함수포인터가 된다.
int func(int x){
return x;
}
이런 func() 함수가 있다고 할 때,
함수포인터를 생성 후 func함수를 연결하는 방법은 밑의 코드다.
int(*fP)(int)=func;
조심해야 할 부분은
int(*fP)(int)=func();
이런 식으로 할당하려는 함수에 괄호를 붙이면 오류가 난다.
일반적으로 배열의 이름이 하는 기능과 비슷하게 함수의 이름은
해당 함수의 포인터가 되서 괄호 없이 이름만 할당해주면 된다.
int(*fP)(int)=func; //fP함수포인터에 func함수 할당
(*fP)(5); //func(5)호출
int(*fP)(int)=func; //fP함수포인터에 func함수 할당
fP(5); //func(5)호출
다른 함수의 인자로 사용되는 함수를 콜백(call-back)함수라고도 부른다.
사용 예를 들면 선택정렬을 할 때
void selectionSort(int* arr,int size)
{
for (int i = 0; i < size; i++) {
//최솟값에 MAX값 넣어줌
min = MAX;
for (int j = i; j < size; j++) {
if (min > arr[j]) {
min = arr[j];
index = j;
}
}
swap(arr[index],arr[i]);
}
}
이렇게 하면 오름차순으로 정렬 되는 코드지만
인자에 bool형 함수포인터를 넣어준 후 오름차순/내림차순 비교함수를 넣어주면
나머지 코드에 영향을 안 주고 방식을 바꿀 수 있다.
void selectionSort(int* arr,int size,bool(*comp)(int,int))
{
for (int i = 0; i < size; i++) {
//최솟값에 MAX값 넣어줌
min = MAX;
for (int j = i; j < size; j++) {
//비교 부분에 함수 포인터 comp사용
if (comp(min, arr[j])) {
min = arr[j];
index = j;
}
}
swap(arr[index],arr[i]);
}
}
//내림차순
bool greater(int x,int y){
return x>y;
}
//오름차순
bool less(int x,int y){
return x<y;
}
이렇게 selectionSort()함수 인자에 bool형 함수포인터를 넣어준 후,
selectionSort의 세번째 인자에 greater을 넘겨주면 내림차순으로 정렬 되고,
less 를 넘겨주면 오름차순으로 정렬된다.
typedef를 사용한는 방법
위의 예시
//위 예시에서 사용한 방식
void selectionSort(int* arr,int size,bool(*comp)(int,int));
typdef를 선언
//typedef로 선언
typedef bool(*comp)(int,int);
//선언 후엔 comp cp로 더 깔끔하게 선언 가능
void selectionSort(int* arr,int size,comp cp);
using 이용 (C++ 11이상)
//using 으로 정의
using comp=bool(*)(int,int);
//typedef 와 동일하게 comp cp 사용
void selectionSort(int* arr,int size,comp cp);
std::function 이용(C++ 11이상)
#include<functional> 헤더를 이용해 사용하는 방식
void selectionSort(int* arr,int size,std::function<bool(int,int)> comp);
넘겨줄 매개변수가 없다면 괄호 안을 비우면 된다.
백준 1697번: 숨바꼭질 문제를 풀던 중 공부한 부분이다.
#include<functional>
const function<int(int)> f[3] = {
[](int n) {return n + 1; },
[](int n) {return n - 1; },
[](int n) {return 2 * n; }
};
이런식으로 function배열 f에 람다함수 형식으로 할당해준 후,
for (int i = 0; i < 3; i++) {
//함수 배열에서 가져와 씀
int nextC = f[i](cur);
f [ i ](int 형 변수)이런식으로 불러와 사용이 가능하다.
int (*f[3])(int);
이런 식으로 선언을 해준다. 크기는 3이고
int형 변수를 매개변수로 받아서 int형을 반환하는 함수의 배열이다.
void init() {
f[0] = [](int n) {return n + 1; };
f[1] = [](int n) {return n - 1; };
f[2] = [](int n) {return 2 * n; };
}
int main()
{
init();
}
std::funcion 처럼 람다를 사용해 바로 초기화는 안 되고,
대신 함수들을 미리 선언해둔 다음 함수 이름을 통해 초기화가 가능하다.
예전에 stl의 sort함수를 [quicksort를 이용해 구현] 해보다가
세번째 인자로 넘겨주는 greater,less함수를 어떻게 구현하는거지 고민을 한참 했었다.
당시엔 결국 구현을 못 하고 디폴트값인 오름차순으로 구현을 했었다.
그 후 시간이 좀 흐르고, c#에서 delegate함수를 배운 후에
c++의 함수포인터를 다시 한번 정리하며 깨달은 부분들을 정리하게 되었다.
확실히 예전에 전공수업으로 c++문법을 배울 땐 왜 함수를 인자로 넣는가 전혀 이해를 못하고
중요하다고 생각하지 않고 넘겼었는 데 막상 구현을 해보니 그 중요성을 깨달았다.