안녕하세요. 명월입니다.
이 글은 C++에서 함수 포인터 사용법에 대한 글입니다.
제가 이전에 포인터와 람다식에 대해서 설명한 적이 있습니다.
링크 - [C++] 배열과 포인터(메모리 주소) 그리고 할당(new){stack과 heap에 대해서}
링크 - [C++] 람다식(functional) 사용법과 클로저(closure) 그리고 auto 자료형
사실 람다식 설명할 때 함수 포인터도 같이 설명을 했어야 했는데.. 정리를 못했네요. 따로 함수 포인터를 정리했습니다.
포인터란 예전에 스택과 힙에서 주소 값을 나타내는 int형 값이라고 설명했습니다. 함수 포인터도 함수를 포인터로 가르킨다는 말 같습니다만 실제로는 다릅니다.
프로그램 언어에서 함수는 힙 메모리에 할당되는 것이 아니고 소스 영역으로 등록이 되는 것이므로 포인터로 메모리의 값을 가르킨다라는 것은 틀립니다.
함수 포인터는 C#의 델리게이트와 같은 의미로 대리자의 의미 입니다. 즉, 메모리를 가르키는 것이 아니고 함수 자체를 가르키는 포인터입니다.
#include <stdio.h>
#include <iostream>
#include <Windows.h>
#include <vector>
#include <crtdbg.h>
// 메모리 릭을 콘솔에 표시하기 위한 함수
#if _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
using namespace std;
// sum 함수 반환 값은 int형이고, 두개의 int형 파라미터를 가지고 있다.
int sum(int a, int b)
{
// 결과는 두 개의 파라미터를 더한다.
return a + b;
}
// subtract 함수 반환 값은 int형이고, 두개의 int형 파라미터를 가지고 있다.
int subtract(int a, int b)
{
// 결과는 두 개의 파라미터를 뺀다.
return a - b;
}
// 실행 함수
int main()
{
// 함수 포인터는 반환형(*)(파라미터)의 형식으로 구성한다.
// vector에 반환형은 int형, int형 파라미터를 두개 가지고 있는 vector를 선언한다.
vector<int(*)(int, int)> list;
// sum 함수는 반환형은 int에 int형의 두개의 파라미터를 가지고 있다.
list.push_back(sum);
// subtract 함수는 반환형은 int에 int형의 두개의 파라미터를 가지고 있다.
list.push_back(subtract);
// 람다식이 두개의 int 파라미터, 반환형을 int로 한다.
list.push_back([](int a, int b)->int
{
// 첫번째 파라미터 * (10 * 두번째 파라미터)
return a * (10 * b);
});
// vector를 iterator로 반복한다.
for (auto ptr = list.begin(); ptr < list.end(); ptr++)
{
// 첫번째 파라미터는 2 두번째 파라미터는 1를 넣는다.
cout << "a , b = " << (*ptr)(2, 1) << endl;
}
_CrtDumpMemoryLeaks();
return 0;
}
결과를 보시면 첫번째는 sum함수가 실행되고 두번째는 subtract함수가 실행되고, 세번째는 람다식이 실행된 것입니다.
함수 포인터는 가운데 * 표시가 있는 것으로 변수형으로 나타낼 수 있습니다.
그렇다면 변수로 사용할 때는 변수명을 「int(*)(int,int) var = sum;」 식으로 사용하지 않습니다.
변수명은 * 표시 바로 뒤에 넣고 선언합니다. 즉, 「int(*var)(int, int) = sum;」 이런 식입니다.
#include <stdio.h>
#include <iostream>
#include <crtdbg.h>
// 메모리 릭을 콘솔에 표시하기 위한 함수
#if _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
using namespace std;
// 실행 함수
int main()
{
// 람다식, int형 파라미터 두개와 반환형 int 함수
// 여기서 변수명은 var입니다.
int(*var)(int, int) = [](int a, int b) -> int {
return a + b;
};
// 콘솔 출력
cout << "a + b = " << var(1, 2) << endl;
_CrtDumpMemoryLeaks();
return 0;
}
함수 포인터는 javascript에서의 콜백 함수 같이 vistor 패턴을 구현할 수 있습니다.
#include <stdio.h>
#include <iostream>
#include <crtdbg.h>
// 메모리 릭을 콘솔에 표시하기 위한 함수
#if _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
using namespace std;
// 예제 함수, 첫번째는 출력을 위한 파라미터, 두번째는 callback 함수
void function(const char* param, void (*cb)(const char*) = nullptr)
{
// 콘솔 출력
cout << "call function param - " << param << endl;
// 콜백 함수가 null이 아니라면
if (cb != nullptr)
{
// 호출
cb(param);
}
}
// callback 함수
void callback(const char* param)
{
// 콘솔 출력
cout << "call callback param - " << param << endl;
}
// 실행 함수
int main()
{
// 예제 함수 호출..
function("hello world");
// 예제 함수 호출, callback을 넣는다.
function("good", callback);
_CrtDumpMemoryLeaks();
return 0;
}
여기서 함수 포인터는 c++의 function 라이브러리로 좀 더 간단하게 표현할 수 있습니다.
#include <stdio.h>
#include <iostream>
#include <crtdbg.h>
// 메모리 릭을 콘솔에 표시하기 위한 함수
#if _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
// 함수 포인터를 간단하게 표현하기 위한 라이브러리
#include <functional>
using namespace std;
// 실행 함수
int main()
{
// 반환형이 int형인 파라미터 int형이 두개인 람다식 함수
function<int(int, int)> var = [](int a, int b) -> int
{
return a + b;
};
// 람다식 호출하면서 콘솔 출력
cout << "a + b = " << var(1, 2) << endl;
_CrtDumpMemoryLeaks();
return 0;
}
사실 이 함수식은 단순히 함수 포인터를 표현하기 좋게 나타내는 것만은 아닙니다.
class의 private기능을 class 선언없이 함수형만으로도 표현할 수 있습니다.
#include <stdio.h>
#include <iostream>
#include <crtdbg.h>
#include <functional>
// 메모리 릭을 콘솔에 표시하기 위한 함수
#if _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
using namespace std;
// 함수를 선택하는 함수
// 여기 반환값을 함수 포인터로 나타내면 에러가 발생한다.
function<void()> select(bool i)
{
// 파라미터가 true의 경우 아래의 함수를 리턴
if (i)
{
return []() -> void {
cout << "bool true function " << endl;
};
}
// false의 경우는 아래의 경우를 리턴
return []() -> void {
cout << "bool false function " << endl;
};
}
// 실행 함수
int main()
{
// select 함수에서 true를 넣고 함수를 리턴해서 실행
select(true)();
// select 함수에서 false를 넣고 함수를 리턴해서 실행
select(false)();
_CrtDumpMemoryLeaks();
return 0;
}
여기까지 C++에서 함수 포인터 사용법에 대한 글이었습니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.
'Study > C , C++ , MFC' 카테고리의 다른 글
[C++] C++에서 Window Form을 생성하는 방법(Win32Api, MFC) (0) | 2020.05.01 |
---|---|
[C++] 소켓(Socket) 통신을 하는 방법 (0) | 2020.04.14 |
[C++] async, promise, future, task의 사용법 (1) | 2020.04.10 |
[C++] map(맵)의 사용법 (0) | 2020.04.09 |
[C++] vector(리스트)의 사용법 (Stack, Queue 알고리즘 예제) (0) | 2020.04.08 |
[C++] 쓰레드(Thread)를 사용하는 방법 (0) | 2020.04.07 |
[C++] IO (fstream)(파일 읽기 쓰기)를 사용하는 방법 (0) | 2020.04.06 |
[C++] 예외처리(try ~ catch, throw) 사용법 (2) | 2020.04.04 |