왜 일반 함수 포인터로는 안 되는가?
함수 종류별 비교
| 구분 | 예시 | 저장 가능한 포인터 타입 |
|---|
| 전역 함수 | int Add(int,int) | int (*)(int,int) |
| 정적 멤버 함수 | static void Foo() | void (*)() |
| 비정적 멤버 함수 | void Player::Attack() | void (Player::*)() |
- 비정적 멤버 함수는 호출 시 객체(
this)가 필요하므로 일반 함수 포인터 타입과 다릅니다.
핵심 직관
- 일반 함수 포인터: "어느 함수로 점프할지"만 알면 됨
- 멤버 함수 포인터: "어느 함수 + 어떤 객체(this)로 호출할지"가 함께 필요
자주 나오는 오류
void (*fp)() = &Player::Attack; -> 컴파일 오류
- 이유:
Player::Attack은 void (*)()가 아니라 void (Player::*)() 타입
멤버 함수 포인터 문법
타입 공식
- 기본형:
ReturnType (ClassName::*)(Args...)
const 멤버 함수: ReturnType (ClassName::*)(Args...) const
기본 예제
class Player {
public:
void Attack(int damage) { hp -= damage; }
int GetHp() const { return hp; }
private:
int hp = 100;
};
using AttackMemFn = void (Player::*)(int);
using GetHpMemFn = int (Player::*)() const;
AttackMemFn attackFn = &Player::Attack;
GetHpMemFn getHpFn = &Player::GetHp;
Player p;
(p.*attackFn)(30);
int hp = (p.*getHpFn)();
Player* pp = &p;
(pp->*attackFn)(10);
호출 연산자 정리
obj.*memFn : 객체가 있을 때
ptr->*memFn : 객체 포인터가 있을 때
오버로드 함수 주의
- 멤버 함수 오버로드가 있으면 함수명만으로 모호할 수 있습니다.
- 필요하면 명시적 캐스팅으로 시그니처를 확정해야 합니다.
실전 활용 패턴
입력-행동 매핑
class Player {
public:
void OnQ() { }
void OnE() { }
};
using Action = void (Player::*)();
unordered_map<char, Action> keyMap = {
{'Q', &Player::OnQ},
{'E', &Player::OnE},
};
char key = 'Q';
Player player;
if (auto it = keyMap.find(key); it != keyMap.end()) {
(player.*(it->second))();
}
- 키 설정만 바꾸면 행동을 갈아끼울 수 있어 입력 커스터마이징에 유리합니다.
Job 큐와 결합할 때
- "행동"만 저장하면 멤버 함수 포인터로도 가능
- 하지만 보통은
"행동 + 대상 + 파라미터"를 함께 저장해야 하므로
다음 Part의 함수 객체(펑터)가 더 자연스럽습니다.
정적 멤버 함수는 예외
static 멤버 함수는 this가 없으므로 일반 함수 포인터에 저장 가능합니다.
한계와 다음 파트 연결
| 한계 | 설명 |
|---|
| 문법 복잡성 | .*, ->*, 타입 선언이 가독성 낮음 |
| 시그니처 제약 | 타입이 조금만 달라도 재사용 어려움 |
| 데이터 바인딩 불편 | 호출 대상/인자를 함께 묶어 다루기 번거로움 |
- 이 한계를 해결하려고 함수 객체(Functor),
lambda, std::function을 사용합니다.
- 다음 Part 4에서 "행동 + 데이터"를 한 객체로 묶는 방식을 학습합니다.
체크 질문 (스스로 답해보기)
- 왜
void (*)()와 void (Player::*)()는 서로 호환되지 않을까?
const 멤버 함수를 가리킬 때 타입 선언이 어떻게 달라질까?
obj.*fn, ptr->*fn를 각각 언제 써야 할까?
- 멤버 함수 포인터만으로 커맨드 큐를 구성할 때 불편한 점은 무엇일까?