함수 포인터 - Function Pointer

함수 포인터 ( Function Pointer ) 에서 가장 헷갈리는 부분은 아마도 Syntax 일 것입니다. 함수 포인터의 Syntax 는 아래와 같습니다.

data-type (*pointerName)(parameters);

1. int (*fcnPtr)(int, std::string);

2. void (*fcnPtr)();

3. bool (*fcnPtr)(std::string);

첫번째로 데이터 타입이 나오며, 그 뒤로 함수 포인터의 이름, 그리고 포인터를 가르키는 * 이 함수 포인터 이름 앞에 붙습니다. 그리고 함수 포인터가 가르키는 함수의 parameter 타입을 정의 합니다. 

 

예를들면 

1. 함수의 리턴형은 int 여야 하고, int 값과 std:string 2개의 파라미터를 받는 함수여야 한다

2. 함수의 리턴형은 void, 파라미터는 받지 않는 함수여야 한다.

3. 함수의 리턴형은 bool 이며, std::string 을 파라미터로 받는 함수여야 한다.

 

함수 포인터에 가장 빠르게 익숙해 지는 방밥은 계속 사용하는 것입니다. 간단한 void 함수를 만든 후 void 함수를 함수 포인터를 할당 후, 함수 포인터를 사용하여 할당된 void 함수를 호출해 보도록 하겠습니다.

#include <iostream>

void firstFunction() {
	std::cout << "first function without any paramter" << std::endl;
}

int secondFunction(int a, int b) {
	return a + b;
}

bool thirdFunction(std::string name) {
	return !name.empty();
}


int main() {
	void (*firstPtr)() = firstFunction; 
    // 리턴타입이 void이며, parameter를 받지 않는 포인터 함수 선언; 선언과 동시에 firstFunction의 주소값을 포인터함수에 할당
	firstPtr();

	int(*secondPtr)(int, int) = secondFunction; 
    // 리턴타입이 int이며, 두개의 int 값을 파라미터로 받는 포인터 함수 선언; 선언과 동시에 secondFunction의 주소값을 포인터 함수에 할당
	std::cout << secondPtr(10, 20) << std::endl;

	bool (*thirdPtr)(std::string) = thirdFunction;
	if (thirdFunction("name")) {
		std::cout << "return value is true" << std::endl;
	}
}

 

함수를 다른 함수의 파라미터로 전달. (Callback Function)Passing functions as arguments to other functions

 

함수 포인터는 다른 함수의 파라미터로 전달 될 수 있으며, 흔히 콜백펑션이라고 부른다. 여기서 중요한 포인트는 함수를 전달 할때 정의되어져 있는 함수포인터의 리턴타입, 파라미터의 값일 정확하게 일치 하여야 한다. 

#include <utility> // for std::swap
#include <iostream>

// 세번째 인자는 포인터 함수로, bool 값을 리턴 하며, 두개의 int 값을 받는 comparisonFcn
void selectionSort(int* array, int size, bool (*comparisonFcn)(int, int))
{
    for (int i = 0; i < (size - 1); ++i)
    {
        int bestIndex = i;

        for (int currentIndex = i + 1; currentIndex < size; ++currentIndex)
        {
            // 세번째 인자로 받은 함수 펑션을 호출한다. comparisonFcn은 두개의 int 값을 비교하여 True or False를 리턴한다.
            if (comparisonFcn(array[bestIndex], array[currentIndex]))
            {
                bestIndex = currentIndex;
            }
        }

        std::swap(array[i], array[bestIndex]);
    }
}

// 오름차순 정렬 함수. X 와 Y 의 값을 비교하여 X 가 Y 보다 클 경우 True를 작을 경우 False를 반환 한다.
bool ascending(int x, int y)
{
    return x > y;
}

// 내림차순 정렬 함수. X 와 Y 의 값을 비교하여 X 가 Y 보다 작을 경우 True를 클 경우 False를 반환 한다.
bool descending(int x, int y)
{
    return x < y; // swap if the second element is greater than the first
}

// 결과 출력 하는 함수
void printArray(int* array, int size)
{
    for (int index{ 0 }; index < size; ++index)
    {
        std::cout << array[index] << ' ';
    }

    std::cout << '\n';
}

int main()
{
    int array[9]{ 3, 7, 9, 5, 6, 1, 8, 2, 4 };

    // descending 함수를 3번재 파라미터로 전달. 
    // selectionSort 함수는 파라미터로 int 타입의 Array, int 값과 , bool (*comparisonFcn)(int, int) 함수 포인터를 받는다.
    selectionSort(array, 9, descending);
    printArray(array, 9);

    // ascending 함수를 3번재 파라미터로 전달. 
    // selectionSort 함수는 파라미터로 int 타입의 Array, int 값과 , bool (*comparisonFcn)(int, int) 함수 포인터를 받는다.
    selectionSort(array, 9, ascending);
    printArray(array, 9);

    return 0;
}

예제에서 보는것과 같이 ascending 함수와 descending 함수를 selectionSort 펑션의 파라미터 값으로 전달을 하여 selectionSort 함수 안에서 ascending과 descending를 호출 하여 사용하는 것을 볼 수 있다.  

 

그렇다면 왜? 이렇게 사용을 하는것일까? 함수 포인터를 사용하게 되면 우리는 다양한 함수를 selectionSort 함수 안에서 콜백펑션으로 사용을 할 수 있다. But 함수의 리턴 타입과 정의되어져 있는 파라미터 값이 일치 해야 한다. 

 

위에서 언급한것과 같이 함수 포인터의 문법은 data-type (*fcnName)(parameters) 이다. 위에 예제에서 보는것과 같이 콜백펑션을 사용 하기 위에 bool (*comparisonFcn)(int, int) 를 파라미터로 정의 하였다. 만약 bool (*comparisonFcn)(int, int) 함수포인터를 전반적인 프로젝트 내에서 사용을 한다고 가정을 하면 코드의 가독성이 떨어진다.

 

이 문제를 해결 하기 위해서 우리는 type aliases를 사용 할 수 있다.

 

bool (*comparisonFcn)(int, int); 함수 포인터는 using comparisonFcn = bool(*)(int, int); 로 바꿀 수 있다.

comparisionFcn은 리턴 타입이 bool 이면서, 두개의 int 파라미터를 가지고 있는 함수를 포인팅 할 수 있다. 

 

Type aliase를 사용하여 우리는 위 예제를 아래와 같이 바꿀 수 있다. 

using comparisonFcn = bool(*)(int, int); 
void selectionSort(int* array, int size, comparisonFcn compare)

 // 이 부분도 comparisonFcn 이 아닌 compare로 바꿔 주어야 한다
 // 세번째 인자로 받은 함수 펑션을 호출한다. comparisonFcn은 두개의 int 값을 비교하여 True or False를 리턴한다.
 if (compare(array[bestIndex], array[currentIndex]))
 {
 	bestIndex = currentIndex;
 }

C++ 11부터 <functional> standard library 에 정의되어져 있는 std::function 을 사용하여 함수 포인터를 정의 할 수 있다.

#include <functional>
bool validate(int x, int y, std::function<bool(int, int)> fcn); 
// std::function 펑션, 리턴 타입은 bool 이며, 두개의 int값을 파라미터로 받고 있다

위에 예문과 같이 < 리턴타입 ( 파라미터1, 파라미터2) > 정의되어져 있다. 만약 파라미터가 없고 bool 값만 리턴 한다면 std::function<bool () > 와같이 정의를 하면 된다. 

std::function<void(const std::string&)> mErrorHandler;
// 리턴 값은 void 이며, const타입의 string 파라미터를 받는 함수 포인터 정의

Type aliasestd::function 을 함께 사용하기.

using comparisonFcn = std::function<bool(int, int)>; 
void selectionSort(int* array, int size, comparisonFcn compare)

 // 이 부분도 comparisonFcn 이 아닌 compare로 바꿔 주어야 한다
 // 세번째 인자로 받은 함수 펑션을 호출한다. comparisonFcn은 두개의 int 값을 비교하여 True or False를 리턴한다.
 if (compare(array[bestIndex], array[currentIndex]))
 {
 	bestIndex = currentIndex;
 }

 

이 포스트의 원문은 www.learncpp.com/cpp-tutorial/78-function-pointers/ 

 

7.8 — Function Pointers | Learn C++

7.8 — Function Pointers By Alex on August 8th, 2007 | last modified by nascardriver on August 8th, 2020 In lesson 6.7 -- Introduction to pointers, you learned that a pointer is a variable that holds the address of another variable. Function pointers are

www.learncpp.com

 

+ Recent posts