5. 객체 슬라이싱(object slicing)과 가상 디스패치

난이도 중 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C++
// ============================================================================
// [언어 내부동작 문제] C++ - 객체 슬라이싱(object slicing)과 가상 디스패치
// ----------------------------------------------------------------------------
// 주제: 파생 객체를 "값"으로 기반 클래스에 복사할 때 일어나는 슬라이싱과, vptr/vtable
//       에 의한 가상 함수 디스패치가 어떻게 정해지는지.
//
// 아래는 몬스터 기반 클래스와 보스 파생 클래스다. 같은 객체를 참조/포인터/값/컨테이너로
// 다룰 때 hp() 가 어떤 구현으로 불리는지 묻는다.
//
// 과제(코드를 고치는 문제가 아니라, 출력과 내부 동작을 예측·설명하는 문제):
//   1) (2)(3)(4)(5) 각 줄의 출력값을 예측하라.
//   2) printHp(Monster m) 처럼 값으로 받을 때, m 의 동적 타입과 vptr 이 어떻게 되는지
//      (왜 Boss::hp 가 불리지 않는지) vtable 관점에서 설명하라.
//   3) std::vector<Monster> 에 Boss 를 push_back 하면 무엇이 저장되는가? 슬라이싱을
//      피하려면 컨테이너/파라미터를 어떻게 설계해야 하는가?
//   (먼저 직접 예측을 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

#include <iostream>
#include <vector>

struct Monster {
    virtual int hp() const { return 100; }
    virtual ~Monster() = default;
};

struct Boss : Monster {
    int extra = 500;
    int hp() const override { return 100 + extra; }   // 600
};

void printHp(Monster m) {                  // 값으로 받음
    std::cout << "printHp: " << m.hp() << "\n";   // (4)
}

int main() {
    Boss b;

    Monster& ref = b;
    std::cout << "ref:  " << ref.hp() << "\n";     // (2)

    Monster* ptr = &b;
    std::cout << "ptr:  " << ptr->hp() << "\n";    // (3)

    printHp(b);                                     // (4) 값 전달

    std::vector<Monster> v;
    v.push_back(b);                                 // 컨테이너에 값 저장
    std::cout << "vec:  " << v[0].hp() << "\n";     // (5)

    return 0;
}
내 리뷰 · C++
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.