필자는 CPP에서 array의 이름이 곧 array의 첫번째 index 원소의 시작 주소임을 알았을때 깜짝 놀랐다. 하지만 이번에 한 번 더 놀랄 일이 있었는데 그건 바로 함수 또한 마찬가지로 함수의 이름이 곧 함수의 저장 위치라는 것이었다. 그리고 이 사실을 기억하고 있으면 함수 포인터를 사용할 때 아주 make-sense하게 사용할 수 있다.
주어진 함수에 대해서 포인터를 만드는 방법은 생긴 것과는 달리 의외로 직관적이다. 함수를 선언하는 것처럼 함수 포인터는 함수 반환타입(*함수 포인터 이름)(함수 인자 , . . . )로 되어 있다. 포인터를 사용할때는 일반 함수를 사용하는 것처럼 함수 포인터 + (인자, . . . )로 사용하면 된다. 백문이 불여일견, 코드를 통해 함수 포인터의 선언과 사용법을 알아보자.
int Sum(int x, int y){
return x+y;
}
// 함수 포인터를 선언하는 법은 함수를 선언하는 순서와 매우 유사하다.
int(*fun_ptr)(int,int);
// 함수의 이름이 곧 함수의 주소라는 사실을 기억!
fun_ptr = Sum;
// 사실상 Sum(10,20)도 함수 주소 + 인자라는 사실을 알면 아래 표현이 전혀 이상하지 않다.
cout << fun_ptr(10,20) << endl;
#include <iostream>
#include <fstream>
using namespace std;
int Sum(int x, int y) {
return x + y;
}
int Minus(int x, int y) {
return x - y;
}
int Multiple(int x, int y) {
return x * y;
}
// type alias를 통해 function pointer의 타입을 지정하고 편하게 쓰자!
using Func_ptr = int(*)(int, int);
int main() {
Func_ptr fun_ptr1 = Sum;
Func_ptr fun_ptr2 = Minus;
Func_ptr fun_ptr3 = Multiple;
// Func_ptr를 받을 수 있는 배열을 만들고 거기에 Sum, Minus, Multiple에 해당하는 함수 포인터들을 저장.
Func_ptr func_array[3] = { fun_ptr1, fun_ptr2, fun_ptr3 };
cout << func_array[0](20, 10) << endl;
cout << func_array[1](20, 10) << endl;
cout << func_array[2](20, 10) << endl;
}
함수 포인터의 개념을 알아도 이를 실전에 어떻게 사용할 지 막막할 것이다. 다음 예시를 통해서 함수 포인터의 엄청난 효용성에 대해 체감해 보자.
이번 코드는 Sum 뿐만 아니라 Minus, Multiple까지 선언된 코드이다. 하지만 유심히 잘 살펴보면, 3개의 함수 다 같은 반환 타입, 변수의 종류와 개수가 동일한 것을 알 수 있다. 이 말은 곧 이 3 함수에 대해 함수 포인터의 형태가 동일하다는 말이다.
만약 이런 경우라면 한 개의 함수 포인터에 대한 타입 정의를 하고 이 사용자 정의 포인터로 Sum, Minus, Multiple에 대해 각각 포인터 설정을 할 수 있다. 더 나아가 아예 이 사용자 정의 포인터를 원소를 가지는 배열을 만들고 거기에 Sum, Minus, Multiple에 해당하는 함수 포인터들을 저장하고 사용할 수 있다.
함수의 parameter 타입이 기본 타입이 아닌 복잡할 경우, 쉽게 function pointer를 만드는 방법이 있다. 바로 인자에서 단순히 변수의 이름만 빼면 파악이 가능하다!
// 다차원 배열의 포인터를 인자로 받는 increase 함수
int increase(int(*arr)[3], int row){};
//위 함수에 대한 function pointer pfunc는 다음과 같다.
int(*pfunc)(int (*)[3], int)