28. 멤버 함수 포인터(pointer-to-member function)의 내부 표현
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C++
// ============================================================================
// [언어 내부동작 문제] C++ - 멤버 함수 포인터(pointer-to-member function)
// ----------------------------------------------------------------------------
// 주제: "일반 함수 포인터"와 "멤버 함수 포인터"는 왜 서로 대입/캐스팅이 안 되고,
// 왜 sizeof 가 다르며, 호출 방식이 왜 다른가?
// - 게임서버에서 흔한 패턴: 패킷 ID -> 핸들러 멤버 함수를 매핑하는 디스패치 테이블
// (예: void (PacketHandler::*)(const Packet&) 를 배열/맵에 저장해 opcode 로 호출).
//
// 과제:
// 1) 아래 main 의 출력을 예측하라.
// 2) sizeof(handler) 가 왜 일반 함수 포인터 sizeof(void*) 와 다를 수 있는지
// (다중 상속/가상 함수가 섞였을 때 컴파일러가 멤버 함수 포인터를 어떻게
// 표현하는지) 내부적으로 설명하라.
// 3) `obj.*handler` / `pobj->*handler` 호출이 실제로 어떤 코드로 치환되는지
// (가상 함수를 가리키는 경우와 비가상 함수를 가리키는 경우의 차이 포함) 설명하라.
// 4) 이 메커니즘을 std::function<void(const Packet&)> 로 대체했을 때
// 생기는 이점과 비용을 설명하라.
// (먼저 직접 예측·설명을 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
#include <cstdio>
struct Packet {
int opcode;
int payload;
};
class PacketHandler {
public:
virtual ~PacketHandler() = default;
void OnMove(const Packet& p) {
std::printf("OnMove payload=%d\n", p.payload);
}
virtual void OnAttack(const Packet& p) {
std::printf("OnAttack(base) payload=%d\n", p.payload);
}
};
class MonsterHandler : public PacketHandler {
public:
void OnAttack(const Packet& p) override {
std::printf("OnAttack(monster) payload=%d\n", p.payload);
}
};
int main() {
// 멤버 함수 포인터 타입: 리턴 타입, 소속 클래스, 파라미터가 모두 타입의 일부다.
void (PacketHandler::* handler)(const Packet&) = nullptr;
Packet p{ /*opcode*/ 1, /*payload*/ 42 };
MonsterHandler monster;
PacketHandler& baseRef = monster;
// (A) 비가상 멤버 함수를 가리키는 포인터
handler = &PacketHandler::OnMove;
(baseRef.*handler)(p);
// (B) 가상 멤버 함수를 가리키는 포인터 — 정적 타입은 PacketHandler 지만
// handler 는 OnAttack 을 가리킨다.
handler = &PacketHandler::OnAttack;
(baseRef.*handler)(p);
std::printf("sizeof(handler) = %zu\n", sizeof(handler));
std::printf("sizeof(void*) = %zu\n", sizeof(void*));
return 0;
} 내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.