[C++]함수 포인터

jh Seo·2022년 8월 3일
1

C++공부

목록 보기
11/21
post-custom-banner

함수 포인터란

함수의 주소를 저장해 함수를 가리키는 포인터이다.

예를 들어, 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();

이런 식으로 할당하려는 함수에 괄호를 붙이면 오류가 난다.

일반적으로 배열의 이름이 하는 기능과 비슷하게 함수의 이름은
해당 함수의 포인터가 되서 괄호 없이 이름만 할당해주면 된다.

함수 포인터를 이용해 함수 사용하기

  1. 역참조를 명시적으로 하는 방법
int(*fP)(int)=func;	//fP함수포인터에 func함수 할당 
(*fP)(5);			//func(5)호출
  1. 암시적으로 역참조하는 방법 ( 일반적으로 하는 함수호출과 동일하다.)
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번: 숨바꼭질 문제를 풀던 중 공부한 부분이다.

std::function을 사용하면

#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++문법을 배울 땐 왜 함수를 인자로 넣는가 전혀 이해를 못하고
중요하다고 생각하지 않고 넘겼었는 데 막상 구현을 해보니 그 중요성을 깨달았다.

레퍼런스

소년코딩님의 블로그(https://boycoding.tistory.com/233)

profile
코딩 창고!
post-custom-banner

0개의 댓글