함수 포인터와 함수 객체 비교
함수 포인터는 함수에 대한 주소값을 저장하는 포인터이다.
표준 C에서는 함수의 인자로 다른 함수의 포인터(함수 포인터)를 받아와 간접 호출할 수 있다.
// ex)
int eval(int a, int b, int (*f)(int,int)) {
return f(a,b);
}
// type: int (*)(int,int)
int add(int a, int b) { return a+b; }
int sup(int a, int b) { return a-b; }
int main() {
cout << eval(4,3,add); // print 7
cout << eval(4,3,sup); // print 1
}
함수 객체는 다른 함수의 인자로 넣을 수 있는 호출 가능한 객체이다.
함수 객체 안에 함수 호출 연산자operator()
를 재정의해 함수 객체를 구현할 수 있다.
// ex)
#include <algorithm>
struct Descending{
bool operator()(int a, int b){ return a > b; }
};
int main() {
int array[] = {7,2,5,1};
std::sort(array, array+4, Descending{});
// 내림차순 정렬{7, 5, 2, 1}
}
// ex) 제네릭을 사용한 예시
struct A {
int x;
A(int x) : x(x) {}
A() : x(0) {};
};
template<typename T, typename F>
T add(T& a, T b, F f) {
return f(a, b);
}
struct Adding {
A& operator()(A& a, const A& b) {
a.x += b.x;
return a;
}
};
int main()
{
A a(10);
A b(20);
A c = add(a, b, Adding{});
cout << c.x << endl;
}
구분 | 함수 포인터 | 함수 객체 |
---|---|---|
안정성 | 제네릭의 경우 인자의 타입을 확인할 수 없음. | template 을 포함한 모든 상황에서 타입 검사가 이루어져 안전함. |
성능 | 함수 인라인화가 불가능해 성능에 좋지 않음. | 함수 객체를 호출한 함수에 operator() 를 삽입하고 컴파일이 진행된다. 그리고 연산자는 인라인화가 가능하기 때문에 함수 포인터보다 좋은 성능을 보여준다. |
상태 유지 | 상태를 가지지 못함. | 클래스 내의 변수 등을 통해 상태를 가질 수 있음. |
.
.
.
C++ 공부를 위해 작성된 글입니다. 오류가 있다면 지적해 주시면 감사하겠습니다.
참고자료
https://github.com/federico-busato/Modern-CPP-Programming