Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 멤버 함수 포인터의 개념과 사용법 완벽 정리

C++에서 클래스나 구조체의 멤버 함수(member function)를 다룰 때는 일반 함수 포인터와 달리 특별한 문법이 필요합니다. 멤버 함수 포인터는 객체 포인터 또는 this 호출을 통해 실행되며, 해당 클래스(또는 그 파생 클래스)의 멤버만 호출할 수 있어 타입 안전성(type safety)이 보장됩니다.

멤버 함수 포인터란?

일반 함수 포인터는 단순히 함수의 주소를 저장하지만, 멤버 함수 포인터는 클래스 범위(class scope)에 속해 있다는 점이 다릅니다. 따라서 선언 시 클래스 이름을 명시해야 하며, 호출할 때도 반드시 객체 또는 객체 포인터가 필요합니다.

  • 선언 형식: 반환타입 (클래스명::*포인터명)(매개변수 목록)
  • 호출 방식: 객체 참조 시 (obj.*fp)(인자), 객체 포인터 사용 시 (obj->*fp)(인자)

예제 코드

아래 예제는 AB 클래스의 두 멤버 함수 subdiv를 함수 포인터를 통해 간접적으로 호출하는 방법을 보여줍니다.

#include <iostream>
using namespace std;

class AB {
public:
    int sub(int a, int b) {
        return a - b;
    }
    int div(int a, int b) {
        return a / b;
    }
};

// 함수 포인터를 매개변수로 받아 멤버 함수 호출
int res1(int m, int n, AB* obj, int(AB::*fp)(int, int)) {
    return (obj->*fp)(m, n);
}

// 함수 포인터를 매개변수로 받아 멤버 함수 호출
int res2(int m, int n, AB* obj, int(AB::*fp2)(int, int)) {
    return (obj->*fp2)(m, n);
}

int main() {
    AB ob;
    cout << "Subtraction is = " << res1(8, 5, &ob, &AB::sub) << endl;
    cout << "Division is = " << res2(4, 2, &ob, &AB::div) << endl;
    return 0;
}

실행 결과

Subtraction is = 3
Division is = 2

코드 설명

1. 멤버 함수 포인터 전달

&AB::sub와 같이 클래스 이름과 범위 지정 연산자(::)를 사용하여 멤버 함수의 주소를 얻습니다. 이 주소는 일반 함수 포인터 변수에 저장할 수 없으며, 반드시 int(AB::*)(int, int) 형태의 멤버 함수 포인터 타입이어야 합니다.

2. 간접 호출 연산자

객체 포인터로 멤버 함수를 호출할 때는 ->* 연산자를 사용합니다. 이는 포인터 역참조와 멤버 접근을 동시에 수행하는 특수 연산자입니다. 만약 객체 자체(포인터가 아닌)를 사용한다면 .* 연산자를 대신 사용합니다.

3. 콜백 및 유연한 설계

이러한 기법은 콜백(callback) 구현, 전략 패턴(Strategy Pattern), 이벤트 핸들링 등 런타임에 호출할 멤버 함수를 동적으로 결정해야 하는 상황에서 유용하게 활용됩니다. 다만 현대 C++에서는 가독성과 유연성이 더 좋은 std::function과 람다(lambda) 표현식을 함께 사용하는 경우가 많습니다.